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
0cff00d
feat(tools): full hosting composition and ingestion package pins
Blind-Striker Aug 11, 2026
1e26366
test(tools): centralized spec scenarios, builders and fixtures
Blind-Striker Aug 11, 2026
b412a2f
refactor(tools): simplify schema requirement check
Blind-Striker Aug 11, 2026
db823d0
build: produce downlevel reference assemblies
Blind-Striker Aug 11, 2026
cb68244
feat(tools): spec reader gate with version, diagnostic and crash walls
Blind-Striker Aug 11, 2026
1d38b5b
docs(plan): correct union graph-key task ordering
Blind-Striker Aug 11, 2026
f91be43
feat(tools): schema wall policy and core schema projection
Blind-Striker Aug 11, 2026
7a737eb
refactor(tools): align test layout and formatting
Blind-Striker Aug 11, 2026
d6bef65
fix(tools): enforce fail-closed schema shape projection
Blind-Striker Aug 11, 2026
e899885
docs(plan): merge coupled schema projection tasks
Blind-Striker Aug 11, 2026
c0d098d
feat(tools): object, literal and union schema projection
Blind-Striker Aug 11, 2026
1934930
feat(tools): per-host walls and operation projection
Blind-Striker Aug 11, 2026
3e21393
docs(spec): walking skeleton design and complexity checkpoint
Blind-Striker Aug 11, 2026
3e6e52e
refactor(tools): replace DOM surveillance walls with semantic-risk ch…
Blind-Striker Aug 11, 2026
011630d
feat(tools): ingestion seam with raw sibling scan and dangling-ref sweep
Blind-Striker Aug 11, 2026
12dd330
test(tools): prefixItems tripwire, boundary guards and pinned-spec la…
Blind-Striker Aug 11, 2026
6c8b720
docs: milestone-driven delivery — specs demoted to vision, slice map …
Blind-Striker Aug 11, 2026
b2fc62c
fix(tests): portable failed-log-file simulation for non-Windows legs
Blind-Striker Aug 11, 2026
2185438
docs(agents): M1 execution handover with course-correction history
Blind-Striker Aug 11, 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
31 changes: 31 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -739,12 +739,43 @@ dotnet_diagnostic.VSTHRD111.severity = none
[tools/opencode-tool.cs]
dotnet_diagnostic.MA0048.severity = none

# Spectre.Console.Cli binds the command-specific settings type declared inside
# its command. Winner: the nested CLI settings contract; CA1034 remains enabled
# for every other file.
[tools/OpenCode.Sdk.Tools/Commands/GenerateCommand.cs]
dotnet_diagnostic.CA1034.severity = none

# The wire-faithful SpecIR primitive-kind contract requires the exact String
# and Integer member names. Winner: the wire-faithful public contract; CA1720
# remains enabled for every other file.
[tools/OpenCode.Sdk.Tools/Generator/Ingestion/Models/PrimitiveKind.cs]
dotnet_diagnostic.CA1720.severity = none

# GraphKeyBuilder centralizes pointer and branch-identity policy shared by projection
# collaborators. Winner: one sealed policy owner instead of duplicated static mechanics;
# static-member rules remain enabled for every other file.
[tools/OpenCode.Sdk.Tools/Generator/Ingestion/Projection/GraphKeyBuilder.cs]
dotnet_diagnostic.CA1822.severity = none
dotnet_diagnostic.S2325.severity = none

# ErrorStyleClassifier is a named policy collaborator constructed by object projection;
# making its only operation static would erase that ownership boundary. Winner: the sealed
# classifier contract; static-member rules remain enabled for every other file.
[tools/OpenCode.Sdk.Tools/Generator/Ingestion/Projection/ErrorStyleClassifier.cs]
dotnet_diagnostic.CA1822.severity = none
dotnet_diagnostic.S2325.severity = none

# EnumSchemaProjector and LiteralClassifier are named schema-policy collaborators composed by
# SchemaProjector; static operations would erase that ownership. Winner: the sealed collaborator
# contracts; static-member rules remain enabled for every other file.
[tools/OpenCode.Sdk.Tools/Generator/Ingestion/Projection/EnumSchemaProjector.cs]
dotnet_diagnostic.CA1822.severity = none
dotnet_diagnostic.S2325.severity = none

[tools/OpenCode.Sdk.Tools/Generator/Ingestion/Projection/LiteralClassifier.cs]
dotnet_diagnostic.CA1822.severity = none
dotnet_diagnostic.S2325.severity = none

# The wire-faithful SpecIR literal-kind contract likewise requires the exact
# String member name. Winner: the wire-faithful public contract; CA1720 remains
# enabled for every other file.
Expand Down
11 changes: 7 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ One line per decision; rationale lives in the ADRs (`docs/adr/`), dated evidence
`docs/research/`. **Reading the ADRs is an integral part of onboarding — do not propose or
change design without knowing them.** Not every locked decision has an ADR (ADRs are created
lazily); this list is the complete inventory of what is settled. Do not reopen without new
evidence. Fine-grained design currently lives in the sealed design specs (transient;
reachable via `docs/ROADMAP.md`) until build-out distills them.
evidence. The design specs under `docs/superpowers/` are vision/reference material —
direction and rationale, not law; only this list and the ADRs bind.

- **Target artifact:** upstream's `packages/sdk/openapi.json` (OpenAPI 3.1), pinned under
`spec/` — the same spec the official JS SDK generates from.
Expand Down Expand Up @@ -56,7 +56,10 @@ reachable via `docs/ROADMAP.md`) until build-out distills them.
- **Testing posture:** borderline-paranoid, fail-closed, defensive by default —
observation-based gates, absolute determinism, fake only published contracts; TUnit on
Microsoft.Testing.Platform, real-process integration, three-OS launcher acceptance
(ADR-0001).
(ADR-0001). Assurance intensity scales with blast radius: shipped SDK runtime highest;
committed generated output next (git diff + analyzer wall + contract tests are its
radar); repo tooling internals lightest — every extra mechanism must name a consumer or
a concrete failure it prevents.

## Hard Rules

Expand Down Expand Up @@ -121,7 +124,7 @@ reachable via `docs/ROADMAP.md`) until build-out distills them.
infrastructure is first-class (central scenario assembly, domain-aware fluent builders;
named scenario classes promoted only on reuse/complexity/domain identity); test data lives
in embedded fixtures, typed builders, or centralized constants — never as inline dumps in
test bodies; TestableIO is the only filesystem seam.
test bodies; Testably supplies the repository's shared `IFileSystem` seam and canonical fake.
- **Test naming:** `{Symbol}_Should_{Expected_Behavior}[_When_{Condition}]`. Symbol names stay
intact as one token (`TryResolve`, `NuGet`); every other word is `_`-separated and starts with
a capital. Example: `TryResolve_Should_Return_False_When_Routes_Are_Invalid`. Test classes are
Expand Down
4 changes: 4 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="TestableIO.System.IO.Abstractions.Analyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
58 changes: 32 additions & 26 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,37 +1,43 @@
<Project>
<ItemGroup>
<!-- third-party analyzers -->
<PackageVersion Include="Meziantou.Analyzer" Version="3.0.140"/>
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="5.6.0"/>
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="10.0.302"/>
<PackageVersion Include="Microsoft.VisualStudio.Threading.Analyzers" Version="18.7.23"/>
<PackageVersion Include="Roslynator.Analyzers" Version="4.15.0"/>
<PackageVersion Include="Roslynator.Formatting.Analyzers" Version="4.15.0"/>
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.31.0.145097"/>
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="1.0.17"/>
<PackageVersion Include="Meziantou.Analyzer" Version="3.0.140" />
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="5.6.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="10.0.302" />
<PackageVersion Include="Microsoft.VisualStudio.Threading.Analyzers" Version="18.7.23" />
<PackageVersion Include="Roslynator.Analyzers" Version="4.15.0" />
<PackageVersion Include="Roslynator.Formatting.Analyzers" Version="4.15.0" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.31.0.145097" />
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="1.0.17" />
<PackageVersion Include="TestableIO.System.IO.Abstractions.Analyzers" Version="2022.0.0" />
<!-- aspire packages -->
<PackageVersion Include="Aspire.Hosting" Version="13.4.6"/>
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.4.6"/>
<PackageVersion Include="Aspire.Hosting" Version="13.4.6" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.4.6" />
<!-- microsoft packages -->
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.10"/>
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.301"/>
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.10" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.301" />
<!-- downlevel targets (netstandard2.0 / net472) -->
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3"/>
<PackageVersion Include="Polyfill" Version="11.0.2"/>
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
<PackageVersion Include="Polyfill" Version="11.0.2" />
<!-- opentelemetry packages -->
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.17.0"/>
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.17.0"/>
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.17.0"/>
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.17.0"/>
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.17.0"/>
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.17.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.17.0" />
<!-- third-party packages -->
<PackageVersion Include="Spectre.Console.Cli" Version="0.55.0"/>
<PackageVersion Include="Spectre.Console.Cli.Extensions.DependencyInjection" Version="0.27.0"/>

<PackageVersion Include="Microsoft.OpenApi" Version="3.9.0" />
<PackageVersion Include="Spectre.Console" Version="0.55.0" />
<PackageVersion Include="Spectre.Console.Cli" Version="0.55.0" />
<PackageVersion Include="Spectre.Console.Cli.Extensions.DependencyInjection" Version="0.27.0" />
<PackageVersion Include="Testably.Abstractions" Version="10.3.0" />
<!-- test packages -->
<PackageVersion Include="Aspire.Hosting.Testing" Version="13.4.6"/>
<PackageVersion Include="NSubstitute" Version="6.0.0"/>
<PackageVersion Include="Spectre.Console.Cli.Testing" Version="0.55.0"/>
<PackageVersion Include="TUnit" Version="1.63.25"/>
<PackageVersion Include="Aspire.Hosting.Testing" Version="13.4.6" />
<PackageVersion Include="NSubstitute" Version="6.0.0" />
<PackageVersion Include="Spectre.Console.Cli.Testing" Version="0.55.0" />
<PackageVersion Include="Testably.Abstractions.Testing" Version="7.0.2" />
<PackageVersion Include="TUnit" Version="1.63.25" />
<PackageVersion Include="Verify.TUnit" Version="31.28.0" />
</ItemGroup>
</Project>
103 changes: 43 additions & 60 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,72 +7,55 @@ Evergreen rules and locked decisions live in `../AGENTS.md`; decision records in

## Status

Structural skeleton in place: `OpenCode.slnx`; `src/OpenCode.Sdk` + `src/OpenCode.Sdk.Extensions`
(empty multi-targeted shells, full TFM matrix); `tests/OpenCode.Sdk.Tests` (TUnit smoke test,
net472 leg Windows-only); three-OS CI (`.github/workflows/ci.yml`: build + test + TRX reporting);
pinned OpenAPI snapshot (`spec/openapi.json`, provenance in `spec/SNAPSHOT.md`). Packages current
as of 2026-08-08. Design runway complete and grill-hardened: three sealed specs under
`superpowers/specs/` (public API, generator architecture, testing architecture), ADRs 0001–0009,
research log sessions 1–14. Implementation planning is maintained in the slice map at
`superpowers/plans/2026-08-10-implementation-slice-map.md` (12 vertical slices), slice issues
**#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. Repo-local Slopwatch pinning, a committed zero-entry
baseline, and the Linux CI gate are active. Slice 1 is ready for execution: the pinned
`Microsoft.OpenApi` reader feeds a fail-closed semantic projection into minimal SpecIR
(ADR-0003; generator spec §4.1); the foundation is the complete PathSmith-shaped ToolApp
host (single production/test composition path, TestableIO, `IAnsiConsole`, MEL
Spectre/optional-file providers, global settings, interceptor); test setup is centralized
and lambda-first, with named scenarios promoted only for reuse, complexity, or durable
domain identity. The wall/tripwire design and the execution plan survived independent
Grok/GLM/Kimi review; the only duplicate removed is Task 8's small-document determinism
assertion, superseded by Task 10's pinned-document repeat (research log sessions 12–14).
The retired parser remains read-only on `feature/slice-01-parser-specir` as evidence; delete
its worktree only with maintainer approval. The corrected plan is
`superpowers/plans/2026-08-11-slice-01-ingestion-specir.md`; issue #2 is
`ready-for-agent`; next is the execution handoff
(`docs/agents/handover-prompts/HANDOFF-2026-08-11.md`).
Structural skeleton, three-OS CI, the pinned spec snapshot, and the Slice 0 tooling skeleton
are in place. The generator-complexity checkpoint (research doc 13; research log session 15)
redirected the build-out: the design specs under `superpowers/` are vision/reference
documents (the sealed surface is the ADRs plus `AGENTS.md`), the slice map is retired in
favor of the milestone list below, and ingestion policy moved from exhaustive DOM
surveillance to semantic-risk fail-closed validation. Slice 1 closed lean on
`feature/slice-01-ingestion-specir`: `ISpecIngestion` projects the complete pin (both
surfaces, landmark smoke green, deterministic) behind the Microsoft.OpenApi boundary
guards; `generate` remains a fail-loud stub until M1's compiler arc. Issue #2 closes with
that branch's PR.

## Queue
## Milestones

In order — do not improvise beyond it without asking the maintainer.
Deliverable-first: every milestone ends in something callable or demonstrable. The next
milestone gets a short (1–2 page) plan when it starts — never earlier. Ordering beyond M2
is revisited at each milestone boundary.

1. **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
`ready-for-agent`). Execution: `subagent-driven-development` per slice on a
`feature/slice-NN-*` worktree branch; one PR to master closes the issue; per-task commits on
the slice branch are the agreed development loop (the `AGENTS.md` commit-rule exception).
TDD for transport/SSE/launcher; `api-design` (extend-only) + `snapshot-testing` (Verify)
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
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
distribution; its SDK usage defines the deep-tested legacy set (ADR-0005). Aspire AppHost
for local dev/test (mini UI, `opencode serve` as a resource) — planned. "opencode HQ" —
multi-instance aggregation above the SDK — is a valued future deliverable in its own
right, not SDK scope.
1. **M1 — Walking skeleton.** `v2.health.get` + `v2.session.message` end to end
(SpecDocument → Binder → EmitPlan → Roslyn emitters → committed source under
`src/OpenCode.Sdk` → minimal transport core → callable client), demonstrated once by
hand against a real `opencode serve` with the output pasted into the PR. Two
independently mergeable arcs: selected compiler + committed models, then the callable
client with typed errors and `NoThrow`. Design reference:
`superpowers/specs/2026-08-11-production-walking-skeleton-design.md`.
2. **M2 — Breadth batches.** The generation profile grows in vertical operation batches;
each batch lands its curation rows, reachable models, operation methods, and contract
tests together.
3. **M3 — Streams.** SSE engine, live/durable subscribe with `after` resume; demo: watching
a real session's event stream. The net472 `ServicePointManager` item lands here.
4. **M4 — Launcher.** `OpenCodeServer.StartAsync` with three-OS acceptance (ADR-0001);
demo: the SDK starts the server itself and calls health. The net472 stdout/tree-kill
items land here.
5. **M5 — Full surface.** Legacy hub, complete generation profile, exclusion fingerprints
(ADR-0008), packaging unblocked.
6. **M6 — Operational closure.** `refresh-spec`, Extensions DI breadth,
retry/telemetry/hooks, quarantine lane, nightly canary; durable decisions distill into
ADRs and the `superpowers/` documents retire.

## Open Questions

- **net472 spike items** — distributed to their SUT slices (slice map, sealed decision 4):
polyfill-set validation + generated-model downlevel compile → slice 3 (the 5-TFM
milestone; checklist in generator spec §12); async stdout reading + `taskkill /T /F`
tree-kill → slice 6; SSE long-lived-response behavior
(`ServicePointManager.DefaultConnectionLimit = 2`) → slice 8.
- **Spec tracking:** `openapi.json` changes on every upstream push — snapshot per SDK release +
diff/regen workflow (`spec/SNAPSHOT.md` is the pin; the submodule tracks upstream). The
`refresh-spec` tool lands in slice 11; the refresh **cadence** policy stays open.
- **Launcher deep-dive items** (public API spec §13; doc 06 §3) — owned by slice 6, including
release-binary confirmation of `--port 0`.
- **Release mechanics** — decided parts live in ADR-0006 (independent semver, per-merge GitHub
Packages CD, manual NuGet.org release pipeline). Still open: pre-1.0/preview numbering,
`VersionPrefix`, RELEASE_NOTES flow, the concrete workflows. **Not covered by the slice
map** — scheduled when the first publishable increment approaches.
- **Spec refresh cadence** — the `refresh-spec` tool lands in M6; the cadence policy stays
open.
- **Structural-union emission shape** — the five structural-union pin sites
(`Config.formatter` et al.) need an emission decision when a breadth batch first reaches
one (a public API review).
- **Release mechanics** — decided parts live in ADR-0006 (independent semver, per-merge
GitHub Packages CD, manual NuGet.org releases). Pre-1.0 numbering, `VersionPrefix`,
RELEASE_NOTES flow, and the concrete workflows are scheduled when the first publishable
increment approaches.
- **Upstream v2 watch:** the active upstream `v2` branch publishes its spec at
`packages/protocol/openapi.json`; its dialect adds single-element `allOf` wrappers
(validation keywords, occasionally with annotations), keeps `v2.`-prefixed operationIds,
Expand Down
12 changes: 8 additions & 4 deletions docs/agents/deviation-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,19 @@ for exactly this case (e.g. the generator spec §3.3 two-condition entry fallbac
state that the trigger fired, and the documents the fallback touches are corrected in the
same change. Add a research-log entry when the evidence is worth keeping.

### Level 2 — Spec correction
### Level 2 — Canonical correction

Reality contradicts a sealed spec claim and no fallback is recorded: upstream behaves
differently, an API does not exist, a verified count is wrong, a design detail cannot be
Reality contradicts a canonical claim — the engineering canon, `CONTEXT.md`, an active
plan's binding constraint, a verified research fact — and no fallback is recorded:
upstream behaves differently, an API does not exist, a count is wrong, a detail cannot be
built as written. **Stop the affected task** (neighboring tasks may continue if
untouched). Capture the evidence — commands, output, source references. Propose the
correction to the maintainer; on approval, the spec/plan is corrected in place and the
correction to the maintainer; on approval, the document is corrected in place and the
task resumes. Findings worth keeping go to the research log.

Vision/reference documents (`docs/superpowers/`) are not protocol subjects: contradicting
one is a level-0 note in the PR, and the document is corrected opportunistically.

### Level 3 — Locked-decision challenge

New evidence contradicts an `AGENTS.md` locked decision or an ADR. **Stop the slice.**
Expand Down
Loading