From 7142fbea3b3637b6322e8da0a662d9b9f5b4f91e Mon Sep 17 00:00:00 2001 From: "denizirgin@gmail.com" Date: Mon, 10 Aug 2026 13:27:19 +0300 Subject: [PATCH 1/8] build(tools): scaffold OpenCode.Sdk.Tools library project --- Directory.Packages.props | 4 ++++ OpenCode.slnx | 3 +++ .../plans/2026-08-10-slice-00-tooling-skeleton.md | 10 +++++----- tools/OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 tools/OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj diff --git a/Directory.Packages.props b/Directory.Packages.props index 32050e37..54710f0b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,6 +13,7 @@ + @@ -24,10 +25,13 @@ + + + diff --git a/OpenCode.slnx b/OpenCode.slnx index dc541485..01744d26 100644 --- a/OpenCode.slnx +++ b/OpenCode.slnx @@ -18,4 +18,7 @@ + + + diff --git a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md index 7f66a78e..ae85224c 100644 --- a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md +++ b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md @@ -56,7 +56,7 @@ Microsoft.Extensions.DependencyInjection, TUnit (already pinned). - Produces: an empty net10.0 library project that later tasks fill; the `/tools/` solution folder. -- [ ] **Step 1: Add package pins to `Directory.Packages.props`** +- [x] **Step 1: Add package pins to `Directory.Packages.props`** Under `` add: @@ -78,7 +78,7 @@ Under `` add: ``` -- [ ] **Step 2: Create `tools/OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj`** +- [x] **Step 2: Create `tools/OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj`** ```xml @@ -100,7 +100,7 @@ Under `` add: (`$(DefaultTargetFramework)` is `net10.0` from `Directory.Build.props`; the tool is single-TFM by design — testing spec §4.) -- [ ] **Step 3: Add the project to `OpenCode.slnx`** +- [x] **Step 3: Add the project to `OpenCode.slnx`** Insert after the `/tests/` folder (folders are kept alphabetical): @@ -110,14 +110,14 @@ Insert after the `/tests/` folder (folders are kept alphabetical): ``` -- [ ] **Step 4: Build** +- [x] **Step 4: Build** Run: `dotnet build --configuration Release` Expected: success, zero warnings (the empty library must pass the wall — if a repo-wide analyzer fires on the bare project, that is a finding, not something to suppress; classify per the deviation protocol). -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add Directory.Packages.props tools/OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj OpenCode.slnx diff --git a/tools/OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj b/tools/OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj new file mode 100644 index 00000000..04fea304 --- /dev/null +++ b/tools/OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj @@ -0,0 +1,14 @@ + + + + $(DefaultTargetFramework) + false + + + + + + + + + From 6fc9efaed30b9c3359df858a5152f3047da07e01 Mon Sep 17 00:00:00 2001 From: "denizirgin@gmail.com" Date: Mon, 10 Aug 2026 13:39:49 +0300 Subject: [PATCH 2/8] feat(tools): ToolApp composition root with fail-loud generate stub --- OpenCode.slnx | 1 + .../2026-08-10-slice-00-tooling-skeleton.md | 14 +++---- .../OpenCode.Sdk.Tools.Tests.csproj | 17 ++++++++ .../OpenCode.Sdk.Tools.Tests/ToolAppTests.cs | 31 ++++++++++++++ .../Commands/GenerateCommand.cs | 25 ++++++++++++ tools/OpenCode.Sdk.Tools/ToolApp.cs | 40 +++++++++++++++++++ 6 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 tests/OpenCode.Sdk.Tools.Tests/OpenCode.Sdk.Tools.Tests.csproj create mode 100644 tests/OpenCode.Sdk.Tools.Tests/ToolAppTests.cs create mode 100644 tools/OpenCode.Sdk.Tools/Commands/GenerateCommand.cs create mode 100644 tools/OpenCode.Sdk.Tools/ToolApp.cs diff --git a/OpenCode.slnx b/OpenCode.slnx index 01744d26..6919fb29 100644 --- a/OpenCode.slnx +++ b/OpenCode.slnx @@ -17,6 +17,7 @@ + diff --git a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md index ae85224c..85eb4339 100644 --- a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md +++ b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md @@ -149,7 +149,7 @@ API note: `CommandAppTester` (ctor taking `ITypeRegistrar`, `Configure`, `RunAsy pinned version's signatures differ in detail (e.g. an added `CancellationToken` on `AsyncCommand.ExecuteAsync`), adapt in place — that is a level-0 deviation. -- [ ] **Step 1: Create the test project** +- [x] **Step 1: Create the test project** `tests/OpenCode.Sdk.Tools.Tests/OpenCode.Sdk.Tools.Tests.csproj`: @@ -179,7 +179,7 @@ Add to `OpenCode.slnx` under the existing `/tests/` folder: ``` -- [ ] **Step 2: Write the failing tests** +- [x] **Step 2: Write the failing tests** `tests/OpenCode.Sdk.Tools.Tests/ToolAppTests.cs`: @@ -218,12 +218,12 @@ public sealed class ToolAppTests (`OpenCode.Sdk.Tools.Tests` sits inside the `OpenCode.Sdk.Tools` namespace hierarchy, so `ToolApp` resolves without a using directive — adding one would trip IDE0005.) -- [ ] **Step 3: Run tests to verify they fail** +- [x] **Step 3: Run tests to verify they fail** Run: `dotnet test tests/OpenCode.Sdk.Tools.Tests` Expected: build FAILS with CS0246 (`ToolApp` not found) — the red state for scaffolding. -- [ ] **Step 4: Implement `ToolApp`** +- [x] **Step 4: Implement `ToolApp`** `tools/OpenCode.Sdk.Tools/ToolApp.cs`: @@ -300,17 +300,17 @@ public sealed class GenerateCommand : AsyncCommand } ``` -- [ ] **Step 5: Run tests to verify they pass** +- [x] **Step 5: Run tests to verify they pass** Run: `dotnet test tests/OpenCode.Sdk.Tools.Tests` Expected: PASS (both tests, net10.0 leg). -- [ ] **Step 6: Full gate check** +- [x] **Step 6: Full gate check** Run: `dotnet build --configuration Release` then `dotnet format --verify-no-changes --no-restore` Expected: both clean. -- [ ] **Step 7: Commit** +- [x] **Step 7: Commit** ```bash git add tools/OpenCode.Sdk.Tools tests/OpenCode.Sdk.Tools.Tests OpenCode.slnx diff --git a/tests/OpenCode.Sdk.Tools.Tests/OpenCode.Sdk.Tools.Tests.csproj b/tests/OpenCode.Sdk.Tools.Tests/OpenCode.Sdk.Tools.Tests.csproj new file mode 100644 index 00000000..f1cd837b --- /dev/null +++ b/tests/OpenCode.Sdk.Tools.Tests/OpenCode.Sdk.Tools.Tests.csproj @@ -0,0 +1,17 @@ + + + + Exe + $(DefaultTargetFramework) + + + + + + + + + + + + diff --git a/tests/OpenCode.Sdk.Tools.Tests/ToolAppTests.cs b/tests/OpenCode.Sdk.Tools.Tests/ToolAppTests.cs new file mode 100644 index 00000000..4354c13c --- /dev/null +++ b/tests/OpenCode.Sdk.Tools.Tests/ToolAppTests.cs @@ -0,0 +1,31 @@ +using Spectre.Console.Cli.Testing; + +namespace OpenCode.Sdk.Tools.Tests; + +public sealed class ToolAppTests +{ + [Test] + public async Task RunAsync_Should_Return_Nonzero_When_Command_Is_Unknown() + { + using var registrar = ToolApp.CreateRegistrar(); + var tester = new CommandAppTester(registrar); + tester.Configure(ToolApp.Configure); + + var result = await tester.RunAsync(["does-not-exist"]); + + await Assert.That(result.ExitCode).IsNotEqualTo(0); + } + + [Test] + public async Task RunAsync_Should_Fail_Loud_When_Generate_Is_Invoked() + { + using var registrar = ToolApp.CreateRegistrar(); + var tester = new CommandAppTester(registrar); + tester.Configure(ToolApp.Configure); + + var result = await tester.RunAsync(["generate"]); + + await Assert.That(result.ExitCode).IsEqualTo(1); + await Assert.That(result.Output).Contains("not implemented"); + } +} diff --git a/tools/OpenCode.Sdk.Tools/Commands/GenerateCommand.cs b/tools/OpenCode.Sdk.Tools/Commands/GenerateCommand.cs new file mode 100644 index 00000000..df921b42 --- /dev/null +++ b/tools/OpenCode.Sdk.Tools/Commands/GenerateCommand.cs @@ -0,0 +1,25 @@ +using Spectre.Console; +using Spectre.Console.Cli; + +namespace OpenCode.Sdk.Tools.Commands; + +/// Fail-loud stub; the generator pipeline replaces the body in a later slice. +public sealed class GenerateCommand : AsyncCommand +{ + private readonly IAnsiConsole _console; + + /// Creates the command; the console is injected so tests capture output. + public GenerateCommand(IAnsiConsole console) + { + ArgumentNullException.ThrowIfNull(console); + _console = console; + } + + /// + protected override Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) + { + _console.MarkupLine( + "[red]generate is not implemented yet[/] — the generator pipeline has not landed."); + return Task.FromResult(1); + } +} diff --git a/tools/OpenCode.Sdk.Tools/ToolApp.cs b/tools/OpenCode.Sdk.Tools/ToolApp.cs new file mode 100644 index 00000000..6ee7dba3 --- /dev/null +++ b/tools/OpenCode.Sdk.Tools/ToolApp.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.DependencyInjection; +using OpenCode.Sdk.Tools.Commands; +using Spectre.Console; +using Spectre.Console.Cli; +using Spectre.Console.Cli.Extensions.DependencyInjection; + +namespace OpenCode.Sdk.Tools; + +/// Composition root for the repo tool: DI registrar plus the command surface. +public static class ToolApp +{ + /// Builds the DI registrar; tests inject service overrides. + public static DependencyInjectionRegistrar CreateRegistrar( + Action? overrideServices = null) + { + var services = new ServiceCollection(); + services.AddSingleton(AnsiConsole.Console); + overrideServices?.Invoke(services); + return new DependencyInjectionRegistrar(services); + } + + /// Registers the command surface; shared by the app and CommandAppTester. + public static void Configure(IConfigurator configurator) + { + ArgumentNullException.ThrowIfNull(configurator); + configurator.SetApplicationName("opencode-tool"); + configurator.AddCommand("generate") + .WithDescription("Regenerate the SDK model layer from spec/openapi.json."); + } + + /// Entry point used by tools/opencode-tool.cs. + public static async Task RunAsync(string[] args) + { + ArgumentNullException.ThrowIfNull(args); + using var registrar = CreateRegistrar(); + var app = new CommandApp(registrar); + app.Configure(Configure); + return await app.RunAsync(args).ConfigureAwait(false); + } +} From 12c177c15f9471d49fc62d6aa82d9b725d27e85a Mon Sep 17 00:00:00 2001 From: "denizirgin@gmail.com" Date: Mon, 10 Aug 2026 13:51:16 +0300 Subject: [PATCH 3/8] feat(tools): file-based entry dogfooding ToolApp --- .editorconfig | 11 +++++++++++ OpenCode.slnx | 1 + .../plans/2026-08-10-slice-00-tooling-skeleton.md | 8 ++++---- tools/opencode-tool.cs | 4 ++++ 4 files changed, 20 insertions(+), 4 deletions(-) create mode 100755 tools/opencode-tool.cs diff --git a/.editorconfig b/.editorconfig index 4c6cba24..2de188ef 100644 --- a/.editorconfig +++ b/.editorconfig @@ -653,6 +653,17 @@ dotnet_diagnostic.MA0201.severity = error dotnet_diagnostic.MA0202.severity = error dotnet_diagnostic.MA0203.severity = suggestion +# ----------------------------------------------------------------------------- +# 10.8 File-based entry arbitration +# ----------------------------------------------------------------------------- +# MA0048 (file name = type name) cannot apply to the file-based tool entry: +# the SDK synthesizes the Program type, and the sealed entry contract pins +# the file name (it is the tool name: ./tools/opencode-tool.cs). Winner: the +# entry contract; the rule stays error for every other file, generated +# output included (emission keeps file = type). +[tools/opencode-tool.cs] +dotnet_diagnostic.MA0048.severity = none + # ============================================================================= # SECTION 11: ROSLYNATOR (RCSxxxx) # ============================================================================= diff --git a/OpenCode.slnx b/OpenCode.slnx index 6919fb29..0770c524 100644 --- a/OpenCode.slnx +++ b/OpenCode.slnx @@ -21,5 +21,6 @@ + diff --git a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md index 85eb4339..ec3c8eb7 100644 --- a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md +++ b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md @@ -331,7 +331,7 @@ git commit -m "feat(tools): ToolApp composition root with fail-loud generate stu pinned invocation forms (`dotnet run --file tools/opencode-tool.cs -- ` on any OS; `./tools/opencode-tool.cs ` on Unix). -- [ ] **Step 1: Write the entry** +- [x] **Step 1: Write the entry** `tools/opencode-tool.cs` — exactly this content, LF line endings, UTF-8 **without BOM** (a BOM breaks the shebang): @@ -349,7 +349,7 @@ Add to the `/tools/` folder in `OpenCode.slnx`: ``` -- [ ] **Step 2: Run through the entry — §3.3 item 1 (strict-props build) + item 3 (invocation form)** +- [x] **Step 2: Run through the entry — §3.3 item 1 (strict-props build) + item 3 (invocation form)** Run: `dotnet run --file tools/opencode-tool.cs -- generate` Expected: exit code 1 and the stub message — proving the entry builds **clean under the @@ -359,7 +359,7 @@ inherited strict props** (any analyzer/TWAE diagnostic fails this run) and that Run: `dotnet run --file tools/opencode-tool.cs -- --help` Expected: exit 0, help output listing `generate`. -- [ ] **Step 3: Commit the executable bit into the index** +- [x] **Step 3: Commit the executable bit into the index** ```bash git add tools/opencode-tool.cs OpenCode.slnx @@ -370,7 +370,7 @@ git ls-files -s tools/opencode-tool.cs Expected: `git ls-files -s` prints mode `100755`. (The bit is meaningless on NTFS and effective on the Linux CI checkout — generator spec §3.1.) -- [ ] **Step 4: Commit** +- [x] **Step 4: Commit** ```bash git commit -m "feat(tools): file-based entry dogfooding ToolApp" diff --git a/tools/opencode-tool.cs b/tools/opencode-tool.cs new file mode 100755 index 00000000..6f85abde --- /dev/null +++ b/tools/opencode-tool.cs @@ -0,0 +1,4 @@ +#!/usr/bin/env -S dotnet -- +#:project ./OpenCode.Sdk.Tools/OpenCode.Sdk.Tools.csproj + +return await OpenCode.Sdk.Tools.ToolApp.RunAsync(args).ConfigureAwait(false); From f29c2244479783d40b5ec1217c717af53d44d49b Mon Sep 17 00:00:00 2001 From: "denizirgin@gmail.com" Date: Mon, 10 Aug 2026 13:59:10 +0300 Subject: [PATCH 4/8] fix(editorconfig): restore global C# analyzer scope after entry arbitration --- .editorconfig | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/.editorconfig b/.editorconfig index 2de188ef..5f8004f9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -653,17 +653,6 @@ dotnet_diagnostic.MA0201.severity = error dotnet_diagnostic.MA0202.severity = error dotnet_diagnostic.MA0203.severity = suggestion -# ----------------------------------------------------------------------------- -# 10.8 File-based entry arbitration -# ----------------------------------------------------------------------------- -# MA0048 (file name = type name) cannot apply to the file-based tool entry: -# the SDK synthesizes the Program type, and the sealed entry contract pins -# the file name (it is the tool name: ./tools/opencode-tool.cs). Winner: the -# entry contract; the rule stays error for every other file, generated -# output included (emission keeps file = type). -[tools/opencode-tool.cs] -dotnet_diagnostic.MA0048.severity = none - # ============================================================================= # SECTION 11: ROSLYNATOR (RCSxxxx) # ============================================================================= @@ -720,3 +709,15 @@ dotnet_diagnostic.MA0042.severity = none dotnet_diagnostic.CA2007.severity = none dotnet_diagnostic.MA0004.severity = none dotnet_diagnostic.VSTHRD111.severity = none + +# ============================================================================= +# FILE-BASED ENTRY ARBITRATION (MA0048) +# ============================================================================= +# Placed after every global C# diagnostic section so the file-scoped glob never +# narrows a later section. MA0048 (file name = type name) cannot apply to the +# file-based tool entry: the SDK synthesizes the Program type, and the sealed +# entry contract pins the file name (it is the tool name: +# ./tools/opencode-tool.cs). Winner: the entry contract; the rule stays error +# for every other file, generated output included (emission keeps file = type). +[tools/opencode-tool.cs] +dotnet_diagnostic.MA0048.severity = none From 5ca3d38b2a8aed48a19d2a0c1655343baca96925 Mon Sep 17 00:00:00 2001 From: "denizirgin@gmail.com" Date: Mon, 10 Aug 2026 14:06:13 +0300 Subject: [PATCH 5/8] docs(research): file-based entry verification results (slice 0) --- docs/research/00-research-log.md | 69 +++++++++++++++++++ .../2026-08-10-slice-00-tooling-skeleton.md | 12 ++-- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/docs/research/00-research-log.md b/docs/research/00-research-log.md index 5592fb3b..2370b137 100644 --- a/docs/research/00-research-log.md +++ b/docs/research/00-research-log.md @@ -970,3 +970,72 @@ TUnit reads arbitrary nested keys via `TestContext.Configuration.Get` — the `testingPlatform.environmentVariables` section did **not** apply and is not relied upon. **Decision:** the TUnit block leaves §14; results recorded at their §5.1/§5.4 use sites. + +# Session 10 — 2026-08-10: slice 0 build-out — file-based entry verification + +Closing session for slice 0's tooling skeleton: ran the generator spec §3.3 three-item +verification list against the committed file-based entry +(`tools/opencode-tool.cs` → `OpenCode.Sdk.Tools` via the `#:project` directive) and +recorded the Task 3 MA0048 arbitration trace in its research home. + +## Q52: Does the file-based entry survive the §3.3 verification list? + +**How researched:** the three §3.3 checks run live against the entry from the repo root. +(1) Strict-props build: `dotnet run --file tools/opencode-tool.cs -- generate` — the +entry inherits `Directory.Build.props` strict props on the cached `dotnet run` path, so a +green build under the full analyzer wall + TWAE is the proof. (2) Cache staleness: with +the entry warm, the `GenerateCommand` stub message was mutated to append +` (cache-probe)` via a file-only edit (no `dotnet build` between edit and re-run), then +the entry was re-run. (3) Invocation forms: `dotnet run --file … -- generate` (any OS) +and `--help` were exercised; the Unix direct-invocation form `./tools/opencode-tool.cs` +was pinned (mode 100755, shebang) but not run on this Windows host — Linux CI runs it in +Task 5. Task 3's strict-props build at session 9 had hit MA0048 on the synthesized +`Program` behind the sealed entry filename; that arbitration is included below as the +required strict-props finding trace. + +**Found (per item):** + +- *Strict-props build verdict:* clean. Post-arbitration, the entry builds under the + inherited strict props with `0 Warning(s) 0 Error(s)` and the fail-loud stub prints + `generate is not implemented yet — the generator pipeline has not landed.` (exit 1, + captured not misclassified). MA0048 (mezintou/Meziantou.Analyzer — "File name must + match type name") fired on the first run because the SDK synthesizes a `Program` type + behind a sealed entry filename no MA0048 mode (`Exact`/`Prefix`/`LongestCommonPrefix`) + can match. Resolved under the analyzer-policy Hard Rule — a file-scoped arbitration + (`.editorconfig`'s last section: `[tools/opencode-tool.cs]` → + `dotnet_diagnostic.MA0048.severity = none`, comment naming the sealed entry contract as + winner) silences it for that file only; MA0048 stays `error` for every other file + (emission file = type commitment intact). This is an arbitration trace, not a policy + rollback — the rule is on for the rest of the codebase, generated output included. The + generator spec's two-condition fallback (console-app promotion) did **not** fire: its + trigger is "the strict-props build cannot be made clean," and the wall *can* be made + clean via its own operating procedure. Initial placement of the file-scoped section + silently narrowed the global `[*.cs]` scope (`.editorconfig` section headers are + cumulative until the next header); a fix-up commit moved the arbitration to the file's + last section so it no longer narrows any subsequent section. + +- *Staleness verdict:* **no mitigation needed.** After the ` (cache-probe)` edit and + re-running `dotnet run --file tools/opencode-tool.cs -- generate` without an + intervening `dotnet build`, the output read + `generate is not implemented yet — the generator pipeline has not landed. + (cache-probe)` (exit 1) — the freshly edited `GenerateCommand` ran. The marker + appeared, so `#:project` library changes trigger rebuilds on the file-based entry path; + the stale-tool hazard does not exist for this entry shape. The generator spec §3.3 + routed-build Level 1 fallback was therefore **not triggered**, and the two-condition + fallback (console-app promotion + ADR-0003 correction) stayed dormant. Probe edit + reverted by apply_patch; the `GenerateCommand.cs` blob was bit-identical pre- and + post-task (SHA256 `de69cb4e…`, git blob `df921b4…`). + +- *Invocation forms:* `dotnet run --file tools/opencode-tool.cs -- generate` exits 1 with + the stub message; `dotnet run --file tools/opencode-tool.cs -- --help` exits 0 with + usage listing `generate — Regenerate the SDK model layer from spec/openapi.json`. The + Unix direct-invocation form `./tools/opencode-tool.cs ` is pinned by mode 100755 + + the `#!/usr/bin/env -S dotnet --` shebang and awaits Linux CI verification in Task 5. + +**Decision:** §3.3 verification list passes; the file-based entry survives as sealed. +Mitigation is **off** — Task 5's CI smoke step does **not** prepend a routed `dotnet +build` line (the spec §3.3 routed-build option is recorded as available but unneeded). +Fallback not triggered; no Level 1 or Level 2 deviation. The MA0048 file-scoped +arbitration is the status quo for this one entry file; if the entry contract ever moves +(e.g. console-app promotion at a future fallback), the arbitration moves with it or is +deleted. diff --git a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md index ec3c8eb7..4684c12f 100644 --- a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md +++ b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md @@ -389,16 +389,16 @@ git commit -m "feat(tools): file-based entry dogfooding ToolApp" - Produces: the recorded §3.3 verdict (research log, question→finding→decision) and, if stale, the mitigation wired into CI/docs in Task 5. -- [ ] **Step 1: Baseline run** +- [x] **Step 1: Baseline run** Run: `dotnet run --file tools/opencode-tool.cs -- generate` — note the message text. -- [ ] **Step 2: Mutate the referenced library without an explicit build** +- [x] **Step 2: Mutate the referenced library without an explicit build** Edit the stub message in `GenerateCommand.cs` to append ` (cache-probe)`. Do **not** run `dotnet build`. Re-run: `dotnet run --file tools/opencode-tool.cs -- generate` -- [ ] **Step 3: Read the verdict** +- [x] **Step 3: Read the verdict** - Marker appears → `#:project` changes trigger rebuilds: **no mitigation needed**. - Marker absent → the stale-tool hazard is real: **mitigation** = every documented/CI @@ -409,12 +409,12 @@ Edit the stub message in `GenerateCommand.cs` to append ` (cache-probe)`. Do **n promotion + one-line ADR-0003 correction) triggers — **stop; maintainer decision** (level 2). -- [ ] **Step 4: Revert the probe edit** +- [x] **Step 4: Revert the probe edit** Revert `GenerateCommand.cs` to Task 2's exact content; re-run the entry once to confirm the original message. -- [ ] **Step 5: Record the findings** +- [x] **Step 5: Record the findings** Append a session entry to `docs/research/00-research-log.md` (next session number, `# Session N — : slice 0 build-out — file-based entry verification`) with one @@ -423,7 +423,7 @@ researched (the three checks above), found (per item: strict-props build verdict staleness verdict, invocation forms), decision (mitigation on/off; fallback not triggered / triggered). -- [ ] **Step 6: Commit** +- [x] **Step 6: Commit** ```bash git add docs/research/00-research-log.md From 32aeb0434fae4abd8275b11ac5aea6d4e0276699 Mon Sep 17 00:00:00 2001 From: "denizirgin@gmail.com" Date: Mon, 10 Aug 2026 14:17:24 +0300 Subject: [PATCH 6/8] docs(research): correct MA0048 classification to Level 1 (slice 0) --- docs/research/00-research-log.md | 42 ++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/docs/research/00-research-log.md b/docs/research/00-research-log.md index 2370b137..183aa545 100644 --- a/docs/research/00-research-log.md +++ b/docs/research/00-research-log.md @@ -1001,18 +1001,21 @@ required strict-props finding trace. captured not misclassified). MA0048 (mezintou/Meziantou.Analyzer — "File name must match type name") fired on the first run because the SDK synthesizes a `Program` type behind a sealed entry filename no MA0048 mode (`Exact`/`Prefix`/`LongestCommonPrefix`) - can match. Resolved under the analyzer-policy Hard Rule — a file-scoped arbitration - (`.editorconfig`'s last section: `[tools/opencode-tool.cs]` → - `dotnet_diagnostic.MA0048.severity = none`, comment naming the sealed entry contract as - winner) silences it for that file only; MA0048 stays `error` for every other file - (emission file = type commitment intact). This is an arbitration trace, not a policy - rollback — the rule is on for the rest of the codebase, generated output included. The - generator spec's two-condition fallback (console-app promotion) did **not** fire: its - trigger is "the strict-props build cannot be made clean," and the wall *can* be made - clean via its own operating procedure. Initial placement of the file-scoped section - silently narrowed the global `[*.cs]` scope (`.editorconfig` section headers are - cumulative until the next header); a fix-up commit moved the arbitration to the file's - last section so it no longer narrows any subsequent section. + can match. Classified as a **Level 1 recorded fallback** (deviation protocol Level 1; + AGENTS.md Hard Rule — "when a rule misfires on real code, the move is a per-rule + arbitration comment naming the winner — never a policy rollback"). The pre-authorized + remedy is a file-scoped arbitration (`.editorconfig`'s last section: + `[tools/opencode-tool.cs]` → `dotnet_diagnostic.MA0048.severity = none`, comment + naming the sealed entry contract as winner); it silences MA0048 for that file only, + and MA0048 stays `error` for every other file (emission file = type commitment + intact). This is a recorded fallback, not a policy rollback — the rule remains on for + the rest of the codebase, generated output included. The §3.3 cache-staleness + fallbacks (routed-build Level 1; console-app promotion + ADR-0003 correction Level 2) + are independent of MA0048 and were not triggered by it: their subject is cache + staleness, evaluated under the staleness check below. Initial placement of the + file-scoped section silently narrowed the global `[*.cs]` scope (`.editorconfig` + section headers are cumulative until the next header); a fix-up commit moved the + arbitration to the file's last section so it no longer narrows any subsequent section. - *Staleness verdict:* **no mitigation needed.** After the ` (cache-probe)` edit and re-running `dotnet run --file tools/opencode-tool.cs -- generate` without an @@ -1033,9 +1036,12 @@ required strict-props finding trace. + the `#!/usr/bin/env -S dotnet --` shebang and awaits Linux CI verification in Task 5. **Decision:** §3.3 verification list passes; the file-based entry survives as sealed. -Mitigation is **off** — Task 5's CI smoke step does **not** prepend a routed `dotnet -build` line (the spec §3.3 routed-build option is recorded as available but unneeded). -Fallback not triggered; no Level 1 or Level 2 deviation. The MA0048 file-scoped -arbitration is the status quo for this one entry file; if the entry contract ever moves -(e.g. console-app promotion at a future fallback), the arbitration moves with it or is -deleted. +Cache mitigation is **off** — Task 5's CI smoke step does **not** prepend a routed +`dotnet build` line; the §3.3 cache-staleness fallbacks were **not triggered** +(marker-present path: routed-build Level 1 unneeded; console-app promotion + ADR-0003 +correction Level 2 dormant). MA0048 is the **one Level 1 recorded fallback executed in +this slice** — pre-authorized by the analyzer-policy Hard Rule's per-rule arbitration +procedure (a recorded fallback, not a policy rollback); the file-scoped arbitration is +the status quo for this one entry file. If the entry contract ever moves (e.g. +console-app promotion at a future cache-Level-2 trigger), the arbitration moves with it +or is deleted. From b95e78ca6b4a7b4bb57e31288941536f32eab094 Mon Sep 17 00:00:00 2001 From: "denizirgin@gmail.com" Date: Mon, 10 Aug 2026 14:26:57 +0300 Subject: [PATCH 7/8] ci: smoke the tooling entry on the Linux leg --- .github/workflows/ci.yml | 6 ++++++ docs/ROADMAP.md | 13 ++++++++----- .../plans/2026-08-10-slice-00-tooling-skeleton.md | 4 ++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b312d372..3665c1b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,6 +70,12 @@ jobs: if: runner.os == 'Linux' run: dotnet format --verify-no-changes --no-restore + # Smoke-runs the repo tooling entry; exercises the committed executable bit and the + # shebang, which only take effect on a Linux checkout. + - name: Tooling entry smoke + if: runner.os == 'Linux' + run: ./tools/opencode-tool.cs --help + # TUnit's always-on HTML report self-uploads as a workflow artifact, but only if these # runtime vars (normally JS/Docker-action-only) are re-exported to run steps. - name: Enable TUnit report artifact upload diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index d9aa472e..36904218 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -15,15 +15,18 @@ as of 2026-08-08. Design runway complete and grill-hardened: three sealed specs `superpowers/specs/` (public API, generator architecture, testing architecture), ADRs 0001–0009, research log sessions 1–9. Implementation planning complete (2026-08-10): slice map at `superpowers/plans/2026-08-10-implementation-slice-map.md` (12 vertical slices), slice issues -**#1–#12** with native `blocked_by` ordering, slice 0 detail plan written (issue #1 is -`ready-for-agent`); deviation protocol added (`docs/agents/deviation-protocol.md`), falsifiability -working agreement added to `AGENTS.md`. No SDK code yet — next up: execute slice 0 (issue #1). +**#1–#12** with native `blocked_by` ordering; deviation protocol added +(`docs/agents/deviation-protocol.md`), falsifiability working agreement added to `AGENTS.md`. +The Slice 0 tooling skeleton has landed; next is the Slice 1 planning cycle for issue #2. ## Queue In order — do not improvise beyond it without asking the maintainer. -1. **SDK build-out — slice issues #1–#12.** Scope, sequencing, and the per-slice done +1. **Post-Slice-0 Slopwatch adoption evaluation.** Decide local-tool pinning, baseline/config, + and CI policy together as one deliberate adoption decision. Do not add a pin, baseline, + configuration, or CI gate until that decision is made. +2. **SDK build-out — remaining slice issues #2–#12.** Scope, sequencing, and the per-slice done definition live in the slice map (`superpowers/plans/2026-08-10-implementation-slice-map.md`); task-level progress lives in per-slice plan checkboxes (plans written just-in-time; a slice whose plan exists gets @@ -34,7 +37,7 @@ In order — do not improvise beyond it without asking the maintainer. lock the public surface as implementation lands (testing spec §12; slices 4–5). **Spec retirement rides slice 11:** durable sealed decisions without an ADR home distill into ADRs before the transient `docs/superpowers/` documents are deleted. -2. **Later** — **MCP server**: in this repo as a thin SDK adapter (ADR-0006). Tech targeting +3. **Later** — **MCP server**: in this repo as a thin SDK adapter (ADR-0006). Tech targeting decided 2026-08-08 (research doc 05), **re-sealed at phase start against the then-current MCP landscape:** the 2026-07-28 protocol revision via MCP C# SDK v2.0, stdio + streamable HTTP, no investment in deprecated features. Evaluate NuGet's `McpServer` package type for diff --git a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md index 4684c12f..14551716 100644 --- a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md +++ b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md @@ -441,7 +441,7 @@ git commit -m "docs(research): file-based entry verification results (slice 0)" - Consumes: the entry + executable bit (Task 3), the staleness verdict (Task 4). - Produces: the Linux-leg smoke step slice 3 will upgrade to `generate --verify`. -- [ ] **Step 1: Add the smoke step** +- [x] **Step 1: Add the smoke step** After the `Verify formatting` step in `.github/workflows/ci.yml`: @@ -461,7 +461,7 @@ If Task 4 recorded the staleness mitigation, prepend the routed build: ./tools/opencode-tool.cs --help ``` -- [ ] **Step 2: Local full-gate sweep** +- [x] **Step 2: Local full-gate sweep** Run, in order: `dotnet build --configuration Release`, `dotnet test --configuration Release --no-build`, `dotnet format --verify-no-changes --no-restore` From 1c4a0d90a9aefe0db807b7e40af172d0d0bc601b Mon Sep 17 00:00:00 2001 From: "denizirgin@gmail.com" Date: Mon, 10 Aug 2026 14:53:55 +0300 Subject: [PATCH 8/8] docs(plan): complete Slice 0 execution checklist --- .../superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md index 14551716..6378cb43 100644 --- a/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md +++ b/docs/superpowers/plans/2026-08-10-slice-00-tooling-skeleton.md @@ -467,7 +467,7 @@ Run, in order: `dotnet build --configuration Release`, `dotnet test --configurat `dotnet format --verify-no-changes --no-restore` Expected: all clean/green. -- [ ] **Step 3: Commit and push the branch** +- [x] **Step 3: Commit and push the branch** ```bash git add .github/workflows/ci.yml @@ -475,7 +475,7 @@ git commit -m "ci: smoke the tooling entry on the Linux leg" git push -u origin feature/slice-00-tooling-skeleton ``` -- [ ] **Step 4: Verify CI** +- [x] **Step 4: Verify CI** Open the PR (`gh pr create`), watch the three legs; the Linux leg must run the smoke step green. Slice exit: PR review + merge closes the slice issue.