Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions .planning/REQUIREMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ Remaining open work (from `FIX-PLAN.md`), batched toward the first `v2.0.0-beta`
- [x] **PKG-02**: Float `Microsoft.Extensions.*` floor per-TFM (`8.0.x` for net8) or justify the pin (A4)
- [x] **SRC-02**: Command-line binder parses quoted values with spaces correctly and skips `arg[0]` (A6)

### Collection & Validation Binding

- [x] **COLL-02**: Unset `T[]`/`List<T>` bind an empty collection, never `null` (only `IEnumerable<T>` does today); fix in `TypeConverter.ConvertValue` null branch (client pre-beta #1)
- [x] **COLL-03**: Bind collections from YAML/child-section sequences via `GetChildren()` in `ConfigurationBinder.BindPropertySettings`; comma-scalar MUST still bind (prod `MultiHost__CommonHosts`); children win over scalar; empty/whitespace/empty-sequence → empty (never `[""]`); each element flows the inner converter chain; re-verify S1/SEC-01 redaction (client pre-beta #2)
- [x] **VAL-01**: Wire `ISettingValidation<T>` + `SettingsPropertyAttribute.ValidatorType` into the populate path so a settings object validates itself incl. cross-property rules (promoted from Held D1; reconcile with the `validate-settings` branch) (client pre-beta #3)
- [x] **VAL-02**: `[SettingsProperty(AllowEmpty=false)]` rejects `""`/whitespace/unsubstituted `${ENV:-}` at bind, not just `null`; `TypeConverter.ValidateNullAcceptance` (naturally rides on VAL-01) (client pre-beta)
- [ ] **API-02**: `AddSimpleSettings(...)` exposes the `ISettingsCollection` (return value or resolvable service — shape TBD in planning) (client pre-beta #4)

### AOT/Trim & Documentation

- [ ] **AOT-01**: Annotate reflection entry points (`[RequiresDynamicCode]`/`[RequiresUnreferencedCode]`) and/or document the AOT/trim limitation before stable (A1)
Expand All @@ -72,7 +80,6 @@ Deferred / held. Tracked but not in the current roadmap.

### Held (do NOT delete)

- **VAL-01**: Wire the `Validations/*` API + `SettingsPropertyAttribute.ValidatorType` into the populate path (reconcile with the `validate-settings` branch) — D1, HELD
- **EQ-01**: Delete or fix+wire `EqualityCompererCreator` (has a latent invalid-IL bug) for value-equality on generated types — D2, HELD

### Deferred
Expand Down Expand Up @@ -104,18 +111,23 @@ Deferred / held. Tracked but not in the current roadmap.
| PKG-01 | Phase 3 | Complete |
| PKG-02 | Phase 3 | Complete |
| SRC-02 | Phase 3 | Complete |
| AOT-01 | Phase 4 | Pending |
| DOC-01 | Phase 4 | Pending |
| REL-01 | Phase 5 | Pending |
| COLL-02 | Phase 4 | Complete |
| COLL-03 | Phase 4 | Complete |
| VAL-01 | Phase 4 | Complete |
| VAL-02 | Phase 4 | Complete |
| API-02 | Phase 4 | Pending |
| AOT-01 | Phase 5 | Pending |
| DOC-01 | Phase 5 | Pending |
| REL-01 | Phase 6 | Pending |

**Coverage:**

- v1 requirements: 15 total
- Mapped to phases: 15
- v1 requirements: 20 total (added Phase 4 engine reqs COLL-02/COLL-03/VAL-02/API-02 + promoted VAL-01 from Held)
- Mapped to phases: 20
- Unmapped: 0 ✓
- Complete: 4 (Phase 1 SEC-01/SEC-02/EXC-01 #27/#28 + ENG-01/T7 #29); Pending: 11
- Complete: 12 (Phase 1 SEC-01/SEC-02/EXC-01 #27/#28; Phase 2 COLL-01/TEST-01/TEST-02/TEST-03 + ENG-01/T7 #29; Phase 3 API-01/PKG-01/PKG-02/SRC-02 #31); Pending: 8 (Phase 4 COLL-02/COLL-03/VAL-01/VAL-02/API-02; Phase 5 AOT-01/DOC-01; Phase 6 REL-01)
- Validated (shipped, no phase): 13

---
*Requirements defined: 2026-07-13*
*Last updated: 2026-07-14 — ENG-01/T7 marked complete (#29). GSD is now the source of truth; FIX-PLAN.md frozen as a historical reference. Reconciled from session handoff + git.*
*Last updated: 2026-07-14 — Phase 4 "Collection & Validation Binding" formalized (COLL-02/COLL-03/VAL-02/API-02 added; VAL-01 promoted from Held D1); AOT/Docs → Phase 5, beta → Phase 6. ENG-01/T7 complete (#29). GSD is the source of truth; FIX-PLAN.md frozen as historical reference.*
57 changes: 45 additions & 12 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

## Overview

**Status (2026-07-14):** Phase 1 shipped (S1 #27, C2 #28); ENG-01/T7 also merged (#29). `master` @ `10f9275`. Active phase is **Phase 2**ENG-01 done; COLL-01 (deferred) + engine tests (TEST-01/02/03) remain.
**Status (2026-07-14):** Phases 1–3 complete (Phase 1 #27/#28, Phase 2 #30, Phase 3 #31; ENG-01/T7 #29). `master` @ `7f9e17c`. Active phase is **Phase 4Collection & Validation Binding** (new engine phase for the client pre-beta requirements); AOT/Trim & Docs renumbered to Phase 5, first beta to Phase 6.

The binding engine already ships and works. This milestone is a hardening + pre-stable
cleanup pass that batches every remaining breaking change and safety fix before cutting the
first `v2.0.0-beta`. It starts by locking the secret-safe exception story and giving
consumers one catchable, structured exception base (Phase 1), proves binding correctness
across collection/nullable/converter shapes and closes the generator concurrency race with
tests (Phase 2), trims and corrects the public surface, packaging, and command-line binder
(Phase 3), tells consumers the truth about AOT/trim and refreshes the docs (Phase 4), and
finally publishes the batched result as the first beta (Phase 5). Everything serves the core
(Phase 3), binds collections and settings validation correctly across empty/sequence/validator
shapes (Phase 4), tells consumers the truth about AOT/trim and refreshes the docs (Phase 5), and
finally publishes the batched result as the first beta (Phase 6). Everything serves the core
value: config → typed settings maps accurately, and never leaks a secret doing it.

## Phases
Expand All @@ -24,8 +25,9 @@ value: config → typed settings maps accurately, and never leaks a secret doing
- [x] **Phase 1: Exception Safety & Public Hierarchy** — ✓ COMPLETE (S1 #27, C2 #28 merged 2026-07-14) - No secret leaks; one catchable, structured `SimpleSettingsException` base
- [x] **Phase 2: Binding Correctness & Engine Test Hardening** - Collections/nullable/converters verified; generator race closed by tests *(ENG-01/T7 done #29; COLL-01 + TEST-01/02/03 remain)* (completed 2026-07-14)
- [x] **Phase 3: Public Surface, Packaging & Binder Cleanup** - Meaningful public surface; per-TFM deps; correct command-line parsing (completed 2026-07-14)
- [ ] **Phase 4: AOT/Trim Honesty & Documentation** - Honest AOT/trim signals; canonically-named docs
- [ ] **Phase 5: First v2.0.0-beta Release** - Batched breaking changes ship as an installable pre-release
- [ ] **Phase 4: Collection & Validation Binding** - Empty/sequence collection binding, working settings validation, and DI collection surface (client pre-beta engine requirements)
- [ ] **Phase 5: AOT/Trim Honesty & Documentation** - Honest AOT/trim signals; canonically-named docs
- [ ] **Phase 6: First v2.0.0-beta Release** - Batched breaking changes ship as an installable pre-release

## Phase Details

Expand Down Expand Up @@ -85,10 +87,40 @@ value: config → typed settings maps accurately, and never leaks a secret doing

- [x] 03-02-PLAN.md — Command-line binder cleanup: SkipFirstArgument option + space-separated `--k v` lookahead + arg[0] skip + AddCommandLine tokenization (SRC-02) [Wave 2, depends on 03-01]

### Phase 4: AOT/Trim Honesty & Documentation
### Phase 4: Collection & Validation Binding

**Goal**: Consumers get honest signals about AOT/trim support and accurate, canonically-named documentation.
**Goal**: Collections bind correctly across empty, comma-scalar, and YAML-sequence shapes; declared settings validation actually runs; and the DI extension exposes the settings collection — the client-requested engine features batched before beta.
**Depends on**: Phase 3
**Requirements**: COLL-02, COLL-03, VAL-01, VAL-02, API-02
**Success Criteria** (what must be TRUE):

1. An unset `T[]` / `List<T>` / `IEnumerable<T>` binds to an empty collection, never `null` (COLL-02).
2. A collection binds from a YAML/child-section sequence (`- a` / `- b`); the comma-scalar form still binds (prod `MultiHost__CommonHosts` unaffected); children win when both exist; each element still flows the inner converter chain (COLL-03).
3. A settings object's declared `ISettingValidation<T>` / `[SettingsProperty(ValidatorType=...)]` is invoked in the bind pipeline, including cross-property rules (VAL-01).
4. `[SettingsProperty(AllowEmpty=false)]` rejects empty / whitespace values at bind, not just `null` (VAL-02). *(Unsubstituted `${ENV:-}` placeholder detection deferred per CONTEXT D-13 — revisit post-beta.)*
5. `AddSimpleSettings(...)` exposes the `ISettingsCollection` (return value or resolvable service) (API-02).
6. After COLL-03 edits `ConfigurationBinder.BindPropertySettings`, the S1/SEC-01 secret-redaction invariant is re-verified; suite green on net8 + net10.

**Plans**: 4/5 plans executed

**Wave 1**

- [x] 04-01-PLAN.md — List<T> family conversion (COLL-01/D-01) + empty-not-null default for array/List/IEnumerable (COLL-02/D-02) [Wave 1]

**Wave 2** *(blocked on Wave 1 completion)*

- [x] 04-02-PLAN.md — Config child-sequence binding via GetChildren() (COLL-03/D-04, D-05) + S1 sequence-element redaction regression (D-06 security gate) [Wave 2, depends on 04-01]
- [x] 04-03-PLAN.md — VAL-01 core path: sync validator contracts + SettingsValidationException + [SettingsValidator]/ValidatorType wired into the populate pipeline incl. cross-property (VAL-01) [Wave 2, depends on 04-01]
- [x] 04-05-PLAN.md — VAL-02: AllowEmpty=false rejects empty/whitespace at bind, value-free (VAL-02/D-13, D-14) [Wave 2, depends on 04-01]

**Wave 3** *(blocked on Wave 2 completion)*

- [ ] 04-04-PLAN.md — API-02 ISettingsCollection exposure (DI singleton + out-overload, D-15) + VAL-01 deferred DI-resolved validator runner (D-11/Q3) [Wave 3, depends on 04-03]

### Phase 5: AOT/Trim Honesty & Documentation

**Goal**: Consumers get honest signals about AOT/trim support and accurate, canonically-named documentation.
**Depends on**: Phase 4
**Requirements**: AOT-01, DOC-01
**Success Criteria** (what must be TRUE):

Expand All @@ -98,10 +130,10 @@ value: config → typed settings maps accurately, and never leaks a secret doing

**Plans**: TBD

### Phase 5: First v2.0.0-beta Release
### Phase 6: First v2.0.0-beta Release

**Goal**: All batched breaking changes and hardening ship as the first pre-release beta consumers can install.
**Depends on**: Phases 1–4 (release gate — all breaking + hardening work complete)
**Depends on**: Phases 1–5 (release gate — all breaking + hardening work complete)
**Requirements**: REL-01
**Success Criteria** (what must be TRUE):

Expand All @@ -115,12 +147,13 @@ value: config → typed settings maps accurately, and never leaks a secret doing
## Progress

**Execution Order:**
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6

| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Exception Safety & Public Hierarchy | n/a (shipped) | ✓ Complete | 2026-07-14 (#27/#28) |
| 2. Binding Correctness & Engine Test Hardening | 2/2 | Complete | 2026-07-14 |
| 3. Public Surface, Packaging & Binder Cleanup | 2/2 | Complete | 2026-07-14 |
| 4. AOT/Trim Honesty & Documentation | 0/TBD | Not started | - |
| 5. First v2.0.0-beta Release | 0/TBD | Not started | - |
| 4. Collection & Validation Binding | 4/5 | In Progress| |
| 5. AOT/Trim Honesty & Documentation | 0/TBD | Not started | - |
| 6. First v2.0.0-beta Release | 0/TBD | Not started | - |
57 changes: 36 additions & 21 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
gsd_state_version: 1.0
milestone: v2.0.0
milestone_name: milestone
current_phase: 4
current_phase_name: AOT/Trim Honesty & Documentation
status: verifying
stopped_at: Phase 3 context gathered
last_updated: "2026-07-14T13:07:28.003Z"
last_activity: 2026-07-14
last_activity_desc: Phase 03 complete, transitioned to Phase 4
current_phase: 04
current_phase_name: collection-validation-binding
status: executing
stopped_at: Completed 04-05-PLAN.md (VAL-02) — Phase 4 all 5 plans done
last_updated: "2026-07-15T13:58:04.988Z"
last_activity: 2026-07-15
last_activity_desc: Phase 04 execution started
progress:
total_phases: 5
total_phases: 6
completed_phases: 2
total_plans: 4
completed_plans: 4
percent: 40
total_plans: 9
completed_plans: 8
percent: 33
---

# Project State
Expand All @@ -24,16 +24,16 @@ progress:
See: .planning/PROJECT.md (updated 2026-07-13)

**Core value:** Correctness of binding — config → strongly-typed settings maps accurately across every supported shape (sections, arrays/enumerables, defaults, nullable, custom converters).
**Current focus:** Phase 03public-surface-packaging-binder-cleanup
**Current focus:** Phase 04collection-validation-binding

## Current Position

Phase: 4 — AOT/Trim Honesty & Documentation
Plan: Not started
Status: Phase complete — ready for verification
Last activity: 2026-07-14 — Phase 03 complete, transitioned to Phase 4
Phase: 04 (collection-validation-binding) — EXECUTING
Plan: 5 of 5
Status: Ready to execute
Last activity: 2026-07-15 — Phase 04 execution started

Progress: [███░░░░░░] 40%
Progress: [███░░░░░░░] 33%

## Performance Metrics

Expand All @@ -60,6 +60,10 @@ Progress: [████░░░░░░] 40%
| Phase 02 P02 | 3min | 1 tasks | 1 files |
| Phase 03 P01 | 3min | 3 tasks | 4 files |
| Phase 03 P02 | 4min | 2 tasks | 4 files |
| Phase 04 P01 | 6min | 2 tasks | 8 files |
| Phase 04 P02 | 12min | 2 tasks | 4 files |
| Phase 04 P03 | 5min | 2 tasks | 10 files |
| Phase 04 P05 | 3min | 1 tasks | 2 files |

## Accumulated Context

Expand All @@ -78,6 +82,13 @@ Recent decisions affecting current work:
- [Phase 02]: TUnit invocation uses --treenode-filter (Microsoft.Testing.Platform); legacy --filter returns zero tests / exit 5.
- [Phase 02]: TEST-03 (Plan 02) scalar Uri/DateTime conversion locked via ScalarConversionTests (Uri->new Uri, DateTime->ParseExact yyyy-MM-dd, one format-mismatch negative asserting exception type only); no array-of-* or redaction duplication. Phase 2 success criterion #5 scalar coverage met on net10 (net8 via CI).
- [Phase 03]: SRC-02 (Plan 02): CLI binder lookahead + split-by-entry-point exe skip. SkipFirstArgument default false (AddArguments binds arg[0]); AddCommandLine sources GetCommandLineArgs() and sets SkipFirstArgument=true internally. Prefixed next-token = new key (diverges from Microsoft). Empty-safe zero-alloc prefix detection; CLI-path secret redaction (S1) held via store-only BindPropertySettings + regression test.
- [Phase ?]: [Phase 04]: COLL-01/COLL-02 (Plan 01): ListTypeConverter handles the List<T> family (List/IList/ICollection/IReadOnlyList/IReadOnlyCollection<T>) via a cached per-element Func<Array,object> factory — no MakeGenericType/Activator on the warm path (S-4/A1). IsListLike is a NEW disjoint predicate (IsEnumerable unchanged, Pitfall 1); IsCollectionShape is the shared shape check COLL-03 reuses.
- [Phase ?]: [Phase 04]: COLL-02 (Plan 01): unbound array/List/IEnumerable bind an empty collection not null; the List null-result is fresh-per-bind (baked Func<object> factory in the existing _nullResult slot, so PropertyPlan[] layout is unchanged) while arrays/IEnumerable keep the shared cached empty array (review B-3).
- [Phase ?]: 04-02: ConfigurationBinder binds collections from child-section sequences (children win, comma-scalar preserved, whitespace/empty -> empty); Binders reuses Core internal IsCollectionShape via InternalsVisibleTo
- [Phase ?]: VAL-01 core path: object + property validators run post-populate, aggregated via shared SettingsValidationException.ThrowIfAny (reused by Plan 04 DI path)
- [Phase ?]: HasValidators short-circuit on the cached plan gates the validation hook before any allocation (protects the B-2 benchmark allocation gate)
- [Phase 04]: 04-05 VAL-02: reuse value-free SettingsPropertyNullException for empty/whitespace rejection — already excluded from the ValuesPopulator:122 redaction filter, so no filter change
- [Phase 04]: 04-05 VAL-02: reject guard placed ahead of 04-01's Func<object> list null-result factory dispatch and gated on _throwOnNull; accept path and factory dispatch untouched

### Pending Todos

Expand All @@ -87,18 +98,22 @@ None yet.

- None blocking. (T7/ENG-01 `SettingsClassGenerator` concurrency race **closed** — shipped pre-GSD via #29: double-checked locking, warm path lock-free, same/distinct-interface `Barrier` stress tests.)

### Roadmap Evolution

- Phase 4 inserted: Phase 4 Collection & Validation Binding formalized (COLL-02/COLL-03/VAL-01/VAL-02/API-02); AOT/Docs renumbered to Phase 5, beta to Phase 6

## Deferred Items

Items acknowledged and carried forward:

| Category | Item | Status | Deferred At |
|----------|------|--------|-------------|
| Held feature | VAL-01 Validations API (D1) | Held (owner-driven) | 2026-07-13 |
| Held feature | VAL-01 Validations API (D1) | Promoted → Phase 4 (2026-07-14) | 2026-07-13 |
| Held feature | EQ-01 EqualityCompererCreator (D2) | Held | 2026-07-13 |
| Perf | PERF-03 compiled setter (P3b) | Deferred (profile-gated) | 2026-07-13 |

## Session Continuity

Last session: 2026-07-14T12:55:01.741Z
Stopped at: Phase 3 context gathered
Resume file: .planning/phases/03-public-surface-packaging-binder-cleanup/03-CONTEXT.md
Last session: 2026-07-15T13:58:04.982Z
Stopped at: Completed 04-05-PLAN.md (VAL-02) — Phase 4 all 5 plans done
Resume file: None
3 changes: 2 additions & 1 deletion .planning/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"post_planning_gaps": true,
"security_enforcement": true,
"security_asvs_level": 1,
"security_block_on": "high"
"security_block_on": "high",
"_auto_chain_active": false
},
"ship": {
"pr_body_sections": [
Expand Down
Loading
Loading