Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e945d99
docs(03): capture phase context
guy-lud Jul 14, 2026
6cbf370
docs(state): record phase 3 context session
guy-lud Jul 14, 2026
d8e7a89
docs(03): research public-surface/packaging/binder cleanup phase
guy-lud Jul 14, 2026
467fbcc
docs: refresh session handoff (Phase 3 — discuss+research done, plann…
guy-lud Jul 14, 2026
f4053e3
docs(phase-3): add validation strategy
guy-lud Jul 14, 2026
6d4dc50
docs(03): create phase plan (public surface, packaging & binder cleanup)
guy-lud Jul 14, 2026
3ba5a8c
docs(03): refine D-05 (split exe-skip by entry point) + resolve open …
guy-lud Jul 14, 2026
ab4a092
docs(03): finalize phase 3 plan (2 plans) after plan-check + architec…
guy-lud Jul 14, 2026
1d2349e
refactor(03-01): make SettingsHolder internal sealed (API-01/D-01)
guy-lud Jul 14, 2026
774bc0e
chore(03-01): remove dead Core.AspNet package (PKG-01/D-02)
guy-lud Jul 14, 2026
2db3bdf
chore(03-01): float Microsoft.Extensions.* floor per-TFM (PKG-02/D-03)
guy-lud Jul 14, 2026
d27602d
docs(03-01): complete public-surface/packaging/binder-cleanup plan
guy-lud Jul 14, 2026
a9558fb
test(03-02): add failing CLI binder cases for lookahead + SkipFirstAr…
guy-lud Jul 14, 2026
29f5469
feat(03-02): add SkipFirstArgument option + lookahead CLI parse (SRC-…
guy-lud Jul 14, 2026
ac537cf
feat(03-02): AddCommandLine sources GetCommandLineArgs + owns exe ski…
guy-lud Jul 14, 2026
d5f9b15
docs(03-02): complete command-line binder cleanup plan
guy-lud Jul 14, 2026
4a8c8de
fix(03-02): null-guard CLI lookahead value token (post-review hardening)
guy-lud Jul 14, 2026
9a1f791
docs(phase-03): complete phase execution (verified 4/4, review clean)
guy-lud Jul 14, 2026
cf69197
docs(backlog): capture client pre-beta engine requirements (COLL/VAL/…
guy-lud Jul 14, 2026
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
16 changes: 8 additions & 8 deletions .planning/REQUIREMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ Remaining open work (from `FIX-PLAN.md`), batched toward the first `v2.0.0-beta`

### Public Surface, Packaging & Binder Cleanup

- [ ] **API-01**: Make `SettingsHolder`/`ISettingsHolder` internal (A5, breaking)
- [ ] **PKG-01**: `Core.AspNet` exposes a public type or the package is dropped (A3)
- [ ] **PKG-02**: Float `Microsoft.Extensions.*` floor per-TFM (`8.0.x` for net8) or justify the pin (A4)
- [ ] **SRC-02**: Command-line binder parses quoted values with spaces correctly and skips `arg[0]` (A6)
- [x] **API-01**: Make `SettingsHolder`/`ISettingsHolder` internal (A5, breaking)
- [x] **PKG-01**: `Core.AspNet` exposes a public type or the package is dropped (A3)
- [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)

### AOT/Trim & Documentation

Expand Down Expand Up @@ -100,10 +100,10 @@ Deferred / held. Tracked but not in the current roadmap.
| TEST-02 | Phase 2 | Complete |
| TEST-03 | Phase 2 | Complete |
| ENG-01 | Phase 2 | ✓ Complete (#29) |
| API-01 | Phase 3 | Pending |
| PKG-01 | Phase 3 | Pending |
| PKG-02 | Phase 3 | Pending |
| SRC-02 | Phase 3 | Pending |
| API-01 | Phase 3 | Complete |
| 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 |
Expand Down
13 changes: 10 additions & 3 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ 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)
- [ ] **Phase 3: Public Surface, Packaging & Binder Cleanup** - Meaningful public surface; per-TFM deps; correct command-line parsing
- [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

Expand Down Expand Up @@ -76,7 +76,14 @@ value: config → typed settings maps accurately, and never leaks a secret doing
3. A net8 consumer is no longer transitively forced onto `Microsoft.Extensions.* 10.x` (per-TFM floor), or the pin is documented with justification.
4. A quoted command-line value containing spaces binds correctly and the executable path (`arg[0]`) is skipped.

**Plans**: TBD
**Plans**: 2/2 plans complete
**Wave 1**

- [x] 03-01-PLAN.md — Public surface & packaging cleanup: SettingsHolder → internal sealed (API-01), drop dead Core.AspNet package (PKG-01), per-TFM Microsoft.Extensions.* floor (PKG-02) [Wave 1]

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

- [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

Expand Down Expand Up @@ -114,6 +121,6 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5
|-------|----------------|--------|-----------|
| 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 | 0/TBD | Not started | - |
| 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 | - |
38 changes: 21 additions & 17 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: 3
current_phase_name: Public Surface, Packaging & Binder Cleanup
current_phase: 4
current_phase_name: AOT/Trim Honesty & Documentation
status: verifying
stopped_at: "Phase 1 (S1 #27, C2 #28) shipped; reconciled ROADMAP/STATE/REQUIREMENTS to mark Phase 1 complete. Next: plan Phase 2."
last_updated: "2026-07-14T10:16:29.256Z"
stopped_at: Phase 3 context gathered
last_updated: "2026-07-14T13:07:28.003Z"
last_activity: 2026-07-14
last_activity_desc: Phase 02 complete, transitioned to Phase 3
last_activity_desc: Phase 03 complete, transitioned to Phase 4
progress:
total_phases: 5
completed_phases: 1
total_plans: 2
completed_plans: 2
percent: 20
completed_phases: 2
total_plans: 4
completed_plans: 4
percent: 40
---

# Project State
Expand All @@ -24,22 +24,22 @@ 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 02binding-correctness-engine-test-hardening
**Current focus:** Phase 03public-surface-packaging-binder-cleanup

## Current Position

Phase: 3Public Surface, Packaging & Binder Cleanup
Phase: 4AOT/Trim Honesty & Documentation
Plan: Not started
Status: Phase complete — ready for verification
Last activity: 2026-07-14 — Phase 02 complete, transitioned to Phase 3
Last activity: 2026-07-14 — Phase 03 complete, transitioned to Phase 4

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

## Performance Metrics

**Velocity:**

- Total plans completed: 2
- Total plans completed: 4
- Average duration: —
- Total execution time: 0 hours

Expand All @@ -48,6 +48,7 @@ Progress: [██░░░░░░░░] 20%
| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| 02 | 2 | - | - |
| 03 | 2 | - | - |

**Recent Trend:**

Expand All @@ -57,6 +58,8 @@ Progress: [██░░░░░░░░] 20%
*Updated after each plan completion*
| Phase 02 P01 | 2min | 3 tasks | 2 files |
| Phase 02 P02 | 3min | 1 tasks | 1 files |
| Phase 03 P01 | 3min | 3 tasks | 4 files |
| Phase 03 P02 | 4min | 2 tasks | 4 files |

## Accumulated Context

Expand All @@ -74,6 +77,7 @@ Recent decisions affecting current work:
- [Phase 02]: ENG-01 verified (not re-implemented): SettingsClassGenerator _generationGate + both concurrency stress tests green — Phase 2 success criterion #4 met by pre-GSD #29.
- [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.

### Pending Todos

Expand All @@ -95,6 +99,6 @@ Items acknowledged and carried forward:

## Session Continuity

Last session: 2026-07-14T10:08:58.479Z
Stopped at: Phase 1 (S1 #27, C2 #28) shipped; reconciled ROADMAP/STATE/REQUIREMENTS to mark Phase 1 complete. Next: plan Phase 2.
Resume file: None
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
45 changes: 45 additions & 0 deletions .planning/backlog/client-requirements-pre-beta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Client requirements — pre-beta engine features (BACKLOG)

**Source:** client (via owner), captured 2026-07-14
**Status:** BACKLOG — to be routed into ROADMAP/REQUIREMENTS after Phase 3 completes.
**Intended window:** before the first `v2.0.0-beta` (this milestone batches breaking changes pre-beta).

> Relationship to existing deferrals: **#1 and #2 pull `COLL-01` (List<T> support) forward and expand it**; **#3 is the held `D1 Validations`**. Recommend inserting a dedicated engine phase before the beta and renumbering the beta phase last. Provisional requirement IDs proposed below — finalize during roadmap integration.

---

## COLL-02 — Empty-collection default *(cheapest; pure win; no back-compat risk)*
- **What:** an unset `T[]` / `List<T>` currently binds `null`; only `IEnumerable<T>` binds empty. Make all three default to an **empty collection, never null**.
- **Where:** `TypeConverter.ConvertValue` null branch. Root cause: `IsEnumerable()` matches only the open `IEnumerable<>` typedef, so arrays / `List<T>` fall through to `return null`. Return `Array.CreateInstance(elementType, 0)` / a new `List<T>` for those.
- **Done when:** unset `T[]`, `List<T>`, `IEnumerable<T>` all bind empty. ~1–2 lines.
- **Unblocks:** gateway drops every `?? []` guard.

## COLL-03 — YAML-sequence / indexed-child binding *(headline readability fix)*
- **What:** collections bind only from a comma-scalar (`"a,b,c"`) today; a readable YAML `- a` / `- b` sequence is silently dropped. Make the binder read **sequence children**.
- **Where:** `ConfigurationBinder.BindPropertySettings` reads a single scalar `section[key]` before conversion runs, so child sections (`key:0`, `key:1`, …) never reach a converter — a converter can't fix this, the **binder** must. Enumerate `GetChildren()` for collection targets.
- **Load-bearing (must keep working):** the comma-scalar form MUST still bind — prod env-var overrides (`MultiHost__CommonHosts`) depend on it.
- **Sub-rules:** children win if both a scalar and children exist; empty / whitespace / empty-sequence → empty (never `[""]`); each element still flows the inner converter chain (so `int[]` / enum arrays keep working); honor `[SettingsSection]` / root prefixing exactly as the scalar path.
- **Unblocks:** revert comma-scalar hacks back to readable sequences in the gateway (`PublicRoute:Routes`, `MultiHost:CommonHosts`, CORS).
- **⚠ Security note:** this changes `BindPropertySettings`, the redaction-critical method Phase 3 left untouched (runs inside the `SettingsBindingException` chaining catch). The S1/SEC-01 secret-redaction invariant MUST be re-verified when this lands.

## VAL-01 — Working class-level / settings-object validation *(= held D1)*
- **What:** `SettingsPropertyAttribute.ValidatorType` and `ISettingValidation<T>` are declared but **never invoked** anywhere in 1.0.0 — dead scaffolding. Wire them into the bind pipeline so a settings object can validate itself (incl. cross-property rules).
- **Where:** invoke the declared validator after conversion/population in the bind flow (today nothing calls it).
- **Unblocks:** gateway Story 8.8 — replace the interim FluentValidation `SpiceDbSettingsValidator` (the PR #103 boot-hook workaround) with the native mechanism.

## VAL-02 — Tighter `AllowEmpty` *(lowest urgency — consumers already fail closed)*
- **What:** `[SettingsProperty(AllowEmpty=false)]` rejects only `null` at bind; an explicit `""`, whitespace, or an unsubstituted `${ENV:-}` placeholder binds clean. Reject those too.
- **Where:** `TypeConverter.ValidateNullAcceptance` (the current null-only check). Naturally rides on VAL-01 if expressed as an `ISettingValidation`.
- **Value:** converts a late runtime failure into a clean startup Fatal. Low urgency because every gateway consumer already denies-all on a blank secret.

## API-02 — Expose `ISettingsCollection` from the DI extension
- **What:** the `AddSimpleSettings` DI extension method should, in the end, expose the `ISettingsCollection` somehow.
- **Where:** DI registration extension (`AddSimpleSettings`).
- **Note:** bundled with the client's item #4; scope/shape (return value vs. resolvable service) to be decided during planning.

---

## Recommended integration (after Phase 3)
1. `/gsd-new-milestone` OR extend the current milestone: add these as REQUIREMENTS.md entries (finalize IDs).
2. Insert a **new engine phase** (collections + validation) before the beta; renumber: current Phase 4 (AOT/docs) and Phase 5 (beta) shift out so the beta stays last.
3. Discuss-phase for the new phase (COLL-02/03 sequencing, VAL-01 pipeline hook point, the S1 re-verification gate for COLL-03).
Loading
Loading