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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI

# Least privilege: every job only reads the repo (no job pushes or needs write).
# Action SHA-pinning / persist-credentials hardening is deliberately deferred to
# a Dependabot/hardening pass — see README "где оно жульничает" item #7.
# a Dependabot/hardening pass — see README "Where it cheats" item #7.
permissions:
contents: read

Expand Down
1,078 changes: 542 additions & 536 deletions README.md

Large diffs are not rendered by default.

828 changes: 828 additions & 0 deletions README.ru.md

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,46 @@ The long-term identity the backlog is aiming at:
> typestate, effects, capabilities, and domain-specific types **without
> rewriting the codebase.**

### Positioning against the competition (not another SAST)

The competition is already standing around this field with shovels and enterprise
sales badges. CodeQL (semantic queries / code scanning), Sonar (quality / bugs /
smells), Semgrep (rule-based AppSec), Snyk Code (SAST), and the AI PR reviewers all
sell the **broad** promise: *"we'll find vulnerabilities / bugs / smells."* Entering
that arena as *"another static analyzer / AI code reviewer / SAST"* is a fight lost
to marketing budget, not to merit.

So Own.NET must **not** be pitched as any of those. The narrower, defensible niche:

> a **cross-language resource / lifetime / effect contract checker** — who holds
> whom, who must release, which resource outlives which, which effect can
> runaway, where a lifecycle contract is broken.

That is a different promise from *"an AI reviewer said this looks suspicious."* And
it is deterministic where the AI reviewers are not — the grown-up framing is *an
LLM may **propose** a suspicious lifecycle contract; Own **verifies** it
deterministically* (reproducible rule, SARIF, suppression/spec, cross-language
model). Not a head-on fight with AI review — a layer underneath it.

### From memory leaks to effect storms (one model, many skins)

The "big idea" that makes the niche coherent: four bugs that look unrelated are the
**same lifecycle/resource-contract failure** in different ecosystems —

| Bug | The contract that broke |
|-----|-------------------------|
| WPF event leak | a long-lived publisher keeps a `ViewModel` alive |
| DI captive dependency | a long-lived service retains a scoped service |
| ArrayPool view-after-return | released backing storage still has a borrowed view |
| **React effect storm** | an unstable dependency repeatedly re-triggers a network effect |

One model (source lifetime / resource / effect / cleanup / stability), one IR
(OwnIR facts), one checker (the `ownlang/` core). The React row is the
Cloudflare-shaped hook — used **honestly**: *"not all lifecycle bugs leak memory;
some leak requests,"* never *"we'd have prevented the Cloudflare outage."* Its
design is [P-020](proposals/P-020-ownts-react-effects.md) (the `Own.React` effect
profile under the OwnTS frontend, [P-017](proposals/P-017-multi-stack-frontends.md)).

## Design philosophy (the load-bearing constraints)

- **One checker.** The Python core in `ownlang/` is the single source of truth.
Expand Down Expand Up @@ -91,6 +131,13 @@ ownership/lifetime/effects, (4) an MVP needs no PhD in Roslyn.
| **P2** | async resource lifecycle; `ValueTask` affine usage; typestate/protocols | [P-008](proposals/P-008-effects-and-resources.md), [P-010](proposals/P-010-type-disciplines.md) |
| **P3** | LOH fragmentation; static-collection memory bloat; cross-thread `ObjectDisposedException` | — (runtime-bound; see detectability matrix) |

> **Are we showable yet?** The concrete "delicious .NET alpha" gate — the A–G bar
> (`dotnet tool` / Action / SARIF / 5 diagnostics / bad-ok examples / case studies /
> suppression policy), the honest current status against it, and the 80/20 rule —
> lives in [docs/notes/alpha-readiness.md](notes/alpha-readiness.md). Short version:
> capability is past alpha; the gap to "people install it" is *packaging* (a single
> `ownsharp check MyApp.sln` CLI, a wedge landing README, packaged case studies).

**The five concrete diagnostics to build first** (balanced across real pain,
architectural strictness, and the borrow-checker showcase):

Expand Down Expand Up @@ -172,6 +219,21 @@ architectural strictness, and the borrow-checker showcase):
Nethermind, AiDotNet.Tensors).
5. **Effects** — `pure` / `use !Db` / `use !Log` / `use Clock`, layer policies
(P-008). The architectural X-ray — landed *after* the leak checkers prove value.
6. **Platform-agnostic core (multi-stack)** — *horizon, on the record for
consideration only.* The same OwnIR seam, reused for non-.NET stacks to prove the
"one core, frontends only extract facts" spine was not .NET-shaped luck (P-017).
Decision recorded: **JS/TS = one frontend family (`OwnTS`), two confidence tiers**
(TS type-aware via the TypeScript Compiler API; JS best-effort via syntax/JSDoc) —
*not* two products; **Java/Kotlin = split frontends** (`OwnJava` via Error Prone/
JDT/Spoon, `OwnKotlin` via Detekt/KSP/K2) **unified by one `OwnJVM` profile** —
because the JVM lifecycle/resource model is shared but the source tooling is not.
The axis the naive layout conflates is **language frontend** (`OwnTS`/`OwnJava`/
`OwnKotlin`) vs **platform profile** (`OwnReact`/`OwnJVM`/`OwnAndroid`/`OwnSpring`)
vs **core** — a brand-per-framework layout "is not a product line, it is a census."
Gated behind a tasty .NET alpha + a real cross-stack bug; the first slices are a
`useEffect`-cleanup *marketing* spike and a listener-leak *research* spike, each
`acquire` without `release` → the existing `OWN001`. See
[P-017](proposals/P-017-multi-stack-frontends.md).

## What static analysis can and cannot catch (the reality matrix)

Expand Down Expand Up @@ -248,3 +310,5 @@ own scan. Label them as estimates wherever they appear.
| [P-014](proposals/P-014-semantic-resolution.md) | Project-local semantic resolution (`+=` event vs number) | P0 | in progress (Tier A default-on + Tier B light path `--ref-dir`; full MSBuild closure deferred) |
| [P-015](proposals/P-015-configuration-surface.md) | Configuration surface (check selection & severity) | P2 | draft (stub) |
| [P-016](proposals/P-016-deep-fact-extraction.md) | Deep C# fact extraction (CFG + flow lowering) | P1 | in progress (B0a/B0b/B2/A1 via `--flow-locals`) |
| [P-017](proposals/P-017-multi-stack-frontends.md) | Multi-stack frontends (OwnTS / OwnJVM: OwnJava + OwnKotlin) | horizon | draft |
| [P-020](proposals/P-020-ownts-react-effects.md) | OwnTS React effects profile (`Own.React`) — effect-storm angle | horizon | draft |
98 changes: 98 additions & 0 deletions docs/notes/alpha-readiness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# "Delicious .NET alpha" — the showable-to-people gate

Working note. The strategy is **not** "spread across stacks" — it is *"make one
stack delicious, and architecturally prove the core isn't bolted to it."* Concretely:
**80% of effort → .NET to "damn, it actually found a leak in my project,"** **20% →
one tiny spike in another stack** to back the platform-agnostic story (P-017/P-020).
A zoo of half-built frontends is cute until you have to deploy it.

This note answers one recurring question — **"are we ready to show people yet?"** —
by pinning a concrete gate and the *honest* current status against it. It is an
assessment, not a promise; status reflects a read of the repo on 2026-06-27.

## The wedge (what we sell, what we refuse to)

Do **not** pitch as: a static analyzer / AI code reviewer / SAST / borrow checker
for C# / multi-language bug finder. That arena belongs to Sonar/CodeQL/Semgrep/Snyk
and their sales teams; see
[ROADMAP — Positioning against the competition](../ROADMAP.md#positioning-against-the-competition-not-another-sast).

Sell the narrow clin:

> **Own.NET finds .NET lifetime/resource bugs: event leaks, timer leaks, missing
> `Dispose`, DI lifetime capture, and pooled-buffer misuse** — the class of bug that
> sends people to dotMemory to argue with their monitor.

Slogans on record (for posts, README, talks):
- *Find leaks before the profiler.*
- *GC collects unreachable objects; Own finds objects that should have become unreachable.*
- *`event +=` is acquire, `-=` is release.*
- *Not all lifecycle bugs leak memory — some leak requests.* (the Cloudflare-style post — P-020)

## The gate (A–G) and where we actually stand

The bar for "showable": a person can reproduce the wow in ~3 minutes
(`install → run → it found my real dirt`).

| | Item | Status (2026-06-27) | Gap to close |
|---|------|--------------------|--------------|
| **A** | `dotnet tool` one-command CLI | ◑ **partial** — the *extractor* is `PackAsTool` (`ownsharp-extract`, P-013); the core is Python. The delightful `ownsharp check MyApp.sln` single tool isn't packaged. | Wrap extractor+core into one `dotnet tool` (or a self-contained CLI) that takes a `.sln`/dir and prints findings. |
| **B** | GitHub Action | ✅ **built** — `action.yml`: `path`/`severity`/`format` (`github` / `msbuild` / `human` / `sarif`), purple shield branding. Matches the "stupidly simple YAML" bar. | Publish to Marketplace; pin the 6-line usage in the README. |
| **C** | SARIF / PR annotations | ✅ **built** — SARIF 2.1.0 + GitHub annotations + reachability/evidence (P-015). | — |
| **D** | 5 core diagnostics | ✅ **built, well past** — OWN001/002/003, OWN014, DI001–005, POOL001–005, WPF001–005 (catalog). The comment's `SUB001/SUB002/TMR001/DISP001/DI001` all exist *semantically*; the `SUB/TMR/DISP` catalog rename is the deferred consolidation item, not new work. | (naming only) land the catalog rename with the OwnIR-v1/profile-label work. |
| **E** | 10 bad/ok examples | ✅ **built** — 12 test-pinned gallery cases (`examples/gallery/`, incl. `00_ok_clean`) + extractor samples. | Add `.cs`-native (not `.own`) bad/ok pairs for the C# audience. |
| **F** | 3 real-world case studies | ◑ **partial** — one honest mining write-up (`real-world-mining.md`: Dapper, CsvHelper, **ScreenToGif** flagship `VideoSource` + two `SystemEvents` leaks, all TPs, clean on disciplined libs) + a 20-case `corpus/real-world/`. Raw material for 3 studies exists; the *packaged* studies don't. | Write 3 `bad → fixed → what others miss → how Own reports it` studies from existing finds. |
| **G** | suppression + false-positive policy | ◑ **partial** — `[OwnIgnore("reason")]` designed (P-004), project-wide config is P-015 (draft); precision behaviour is strong & documented ("no FP from `using`"). | One consolidated user-facing page: suppression mechanism + explicit FP policy. |

**Plus the front door (not in A–G but the real blocker):** `README.md` is now
bilingual (English default + a `README.ru.md` variant), but still `# OwnLang — PoC` —
deep, research-framed, no wedge landing. There is **no 20-second landing /
copy-paste install / Action quickstart** at the top. Per the comment's own
open-source-path list (README-in-20s → copy-paste → bad/ok → Action → SARIF →
suppression → "why not Sonar/CodeQL"), this is the highest-leverage missing piece.

## Honest verdict

**The engine is past alpha on *capability* (D/E strong, B/C built). The gap to
"showable" is *packaging and presentation*, not analysis power:**

1. a single `ownsharp check MyApp.sln` tool (**A**);
2. a wedge landing README + copy-paste quickstart (front door);
3. three packaged case studies from finds we already have (**F**);
4. one consolidated suppression / false-positive page (**G**).

None of those is research; all are the difference between "interesting PoC" and
"people install it." That ordering *is* the day 1–30 milestone.

## The 20% rule (other stacks)

Other stacks are **proof of portability, not a second product.** Sanctioned now:
**at most one rule each**, as experiments — not an OwnTS 1.0.

```
experiments/
owents-react-effect-cleanup/ # P-020: useEffect listener/effect, the PR/marketing spike
ownjava-listener-leak/ # P-017: addListener w/o removeListener → same OwnIR, the model proof
```

README framing, and no more: *"Experimental: the same OwnIR model can represent
React effect cleanup and Java listener lifetimes."* Design lives in
[P-017](../proposals/P-017-multi-stack-frontends.md) /
[P-020](../proposals/P-020-ownts-react-effects.md); both stay `horizon`/`draft`
until the .NET alpha above is delicious. Do not let the spike exceed 20%.

## 90-day shape (sequencing, not a schedule)

- **Days 1–30 — make the .NET alpha tasty:** close A, the README front door, F, G
(B/C/D/E already done). Suppression UX + bad/ok corpus polish.
- **Days 31–60 — real-world proof:** run over 20–50 OSS .NET/WPF/Avalonia/WinForms
repos; table of findings / confirmed / FP / unsupported; 2 case studies; compare
with CodeQL / NetAnalyzers / Infer# where possible (the oracle, `docs/notes/oracle.md`).
- **Days 61–90 — public launch:** landing README, "WPF zombie ViewModels" post,
HN/Reddit/dev.to/.NET community, Action on Marketplace, `good first spec` issues,
feedback from WPF/Avalonia/WinForms maintainers. The React/Java spike runs in
parallel — capped at 20%.

The standing priority is unchanged: **prove value, don't reshape form**
([consolidation-and-positioning.md](consolidation-and-positioning.md)). This note is
the concrete "what value, packaged how" gate for that.
Loading
Loading