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
46 changes: 46 additions & 0 deletions .github/workflows/h28-command-falsifier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: H-28 DbCommand falsifier

on:
pull_request:
paths:
- '.github/workflows/h28-command-falsifier.yml'
- 'corpus/ownership-lab/h28-command/**'
- 'frontend/roslyn/OwnSharp.Extractor/**'
- 'ownlang/**'
- 'docs/notes/h28-npgsql-command-resolution.md'
workflow_dispatch:

permissions:
contents: read

jobs:
h28-required-gates:
name: H-28 required runtime + extractor gates
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.11'
- uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4
with:
dotnet-version: '8.0.x'
- name: Install self-contained PostgreSQL 16 harness
run: python -m pip install 'pgserver==0.1.4'
- name: Run mandatory G1-G3 gates (SKIP is failure)
run: corpus/ownership-lab/h28-command/run.sh all-required
- name: Preserve source facts and runtime observations
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: h28-command-falsifier
if-no-files-found: warn
path: |
corpus/ownership-lab/h28-command/evidence/g3-CommandDispose.facts.json
corpus/ownership-lab/h28-command/evidence/g3-CommandDispose.summaries.json
corpus/ownership-lab/h28-command/evidence/g3-CommandDispose.sarif.json
corpus/ownership-lab/h28-command/evidence/g3-CommandDispose.log
corpus/ownership-lab/h28-command/evidence/g3-*.log
corpus/ownership-lab/h28-command/evidence/runtime-*.log
corpus/ownership-lab/h28-command/evidence/runtime-*.out
76 changes: 76 additions & 0 deletions corpus/ownership-lab/h28-command/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
H-28-CMD: the DbCommand half of the `DataTable.Load(reader)` family.

STATUS
Final verdict: H28-PROVIDER-SPECIFIC, narrowly bounded to Npgsql 10.0.3/PostgreSQL 16 and
Microsoft.Data.Sqlite 10.0.12. Required G1-G3 passed in PR workflow run #38048287923; its
`h28-command-falsifier` artifact contains runtime logs, OwnIR facts, summaries and SARIF. This
does not label OWN001 a false positive or establish a universal provider rule. Read
docs/notes/h28-npgsql-command-resolution.md before interpreting any artifact.

The original H-28 (research/ownership-semantics-lab-v1@298b305, not on main) settled
`DataTable.Load(reader)` for a one-result reader: it IS closed (`RELEASE_IF_LAST_RESULT_SET`,
not BORROW). That same record wrote down one sentence and never classified it:

"what remains is the never-disposed DbCommand `cmd` (an object leak without a
protocol consequence)"
-- h28/scripts/h28_anchors_record.py, consequence_for_the_demanding_instance

This directory records falsifiable source and runtime checks. It does not call OWN001 a false
positive, claim a native leak on Npgsql, or propose a universal rule from these provider runs.

LAYOUT
fx/CommandDispose.cs nine C# methods (A/B/C/D + controls), using abstract ADO.NET types.
G3 confirmed the expected finding anchors in workflow run #38048287923.
fx/CommandDispose.own engine-only manual reduction. This is not C# extraction evidence.
falsifier/Program.cs P1-P5 and G2/P6. P4 is isolated from P1-P3; P6 counts live SQLite
statements via sqlite3_next_stmt, not RSS or forced GC.
falsifier/h28cmd.csproj net8.0, Npgsql 10.0.3, Microsoft.Data.Sqlite 10.0.12; compiles
both the falsifier and fx/CommandDispose.cs.
falsifier/run_with_pgserver.py
keeps the temporary pgserver alive while the .NET test runs.
scripts/verify_g3.py production Roslyn -> OwnIR -> summaries -> core SARIF; exact expected
finding anchors are checked, and all intermediate artifacts saved.
scripts/derive_source_evidence.py
re-fetches 44 upstream excerpts plus the Npgsql finalizer negative
scan. Includes the SQLitePCLRaw opt-in required by sqlite3_next_stmt;
TFM evidence confirms Npgsql 10.0.3 targets net8.0 and
Microsoft.Data.Sqlite 10.0.12 has a netstandard2.0 asset usable by
this net8.0 falsifier. Non-zero = drift.
run.sh PASS/FAIL/SKIP driver. `all-required` fails on any SKIP.
evidence/*.txt source excerpts with repository/ref/path/git blob sha/file sha256/
line range. Local engine output is saved. G3/runtime artifacts are
produced in CI and attached to workflow run #38048287923.
.github/workflows/h28-command-falsifier.yml
runs `all-required` on the PR and preserves results as an artifact.

GATES
./corpus/ownership-lab/h28-command/run.sh engine # Python only; current manual core pass
./corpus/ownership-lab/h28-command/run.sh g3-required # production extractor and core
./corpus/ownership-lab/h28-command/run.sh runtime-required # compile + provider runtime
./corpus/ownership-lab/h28-command/run.sh all-required # mandatory; SKIP is non-zero
python3 corpus/ownership-lab/h28-command/scripts/derive_source_evidence.py

Runtime dependencies: .NET 8 SDK, packages available from NuGet or already restored in cache,
and PostgreSQL 16. The workflow installs pinned pgserver 0.1.4 from PyPI; locally either
`pip install pgserver==0.1.4` or set H28_PG_DSN. There is no curl-only NuGet gate: the script attempts restore with
`--ignore-failed-sources`, so a warm package cache can work offline.

WHAT HAS RUN IN THE PRODUCING SANDBOX
PASS: Python engine reduction, matching three manual OWN001 expectations; 33/33 real-world
corpus cases; whole-tree Ruff; mypy (60 source files); 44 source excerpts + finalizer scan;
Python/shell syntax checks, C# grammar parse (not compilation), and pgserver supervisor
API/Unix-socket DSN preflight (not a .NET/provider falsifier).
PASS IN CI: G1 build/P4, G2 native SQLite statement checks, P5 PostgreSQL prepared-state check,
and G3 production C# extraction all passed in workflow run #38048287923. The exact
artifact is attached to that run; local status metadata is evidence/ci-run-38048287923.txt.
BLOCKED LOCALLY: this sandbox has no .NET SDK, so its `all-required` run returned 1 on G1/G2/G3
SKIPs; see evidence/required-gates-local.txt.
INCOMPLETE: `python tests/run_tests.py` passed its early analysis/codegen checks, then stopped at
checkpoint validation because this checkout is shallow and `cargo` is absent. It is
not counted as a green full-suite run. See evidence/local-validation.txt.

SCOPE
No production analyzer code, OwnIR vocabulary, ownership semantics, or diagnostics are changed.
The normal real-world corpus suite does not glob `corpus/ownership-lab/`; these are experiment
fixtures. G3 now confirms the predicted extraction loss on this exact fixture. Any architecture
follow-up, including #382, remains separate and is not proposed or implemented in this PR.
47 changes: 47 additions & 0 deletions corpus/ownership-lab/h28-command/evidence/MANIFEST.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# H-28-CMD source evidence manifest (declared refs).
# OK/SCAN = re-derived now; MISSING/MARKER-NOT-FOUND = stale or unavailable.
OK npgsql-v10.0.3-target-frameworks.txt npgsql/npgsql@v10.0.3 sha256=fd36c9e18a2c4765 lines=8
OK npgsql-10.0.3-NpgsqlCommand-Dispose.txt npgsql/npgsql@v10.0.3 sha256=6bdde5901d32a633 lines=1712
OK npgsql-10.0.3-NpgsqlCommand-Reset.txt npgsql/npgsql@v10.0.3 sha256=6bdde5901d32a633 lines=1728
OK npgsql-10.0.3-NpgsqlCommand-ctor-SuppressFinalize.txt npgsql/npgsql@v10.0.3 sha256=6bdde5901d32a633 lines=120
OK npgsql-10.0.3-NpgsqlCommand-CreateCachedCommand.txt npgsql/npgsql@v10.0.3 sha256=6bdde5901d32a633 lines=166
OK npgsql-10.0.3-NpgsqlCommand-TraceCommandStart.txt npgsql/npgsql@v10.0.3 sha256=6bdde5901d32a633 lines=1748
OK npgsql-10.0.3-NpgsqlCommand-TraceCommandStop.txt npgsql/npgsql@v10.0.3 sha256=6bdde5901d32a633 lines=1792
OK npgsql-10.0.3-NpgsqlConnection-CreateCommand.txt npgsql/npgsql@v10.0.3 sha256=02ed57055a9e1f02 lines=549
OK npgsql-10.0.3-NpgsqlDataReader-Dispose.txt npgsql/npgsql@v10.0.3 sha256=9c109626d6627b55 lines=1008
OK npgsql-10.0.3-NpgsqlDataReader-DisposeAsync.txt npgsql/npgsql@v10.0.3 sha256=9c109626d6627b55 lines=1037
OK npgsql-10.0.3-NpgsqlDataReader-Close-public.txt npgsql/npgsql@v10.0.3 sha256=9c109626d6627b55 lines=1073
OK npgsql-10.0.3-NpgsqlDataReader-Cleanup.txt npgsql/npgsql@v10.0.3 sha256=9c109626d6627b55 lines=1141
OK npgsql-10.0.3-NpgsqlActivitySource-IsEnabled.txt npgsql/npgsql@v10.0.3 sha256=b7ef8df7f2f66573 lines=17
OK npgsql-10.0.3-NpgsqlActivitySource-SourceName.txt npgsql/npgsql@v10.0.3 sha256=b7ef8df7f2f66573 lines=15
OK npgsql-10.0.3-NpgsqlConnector-PreparedStatementManager.txt npgsql/npgsql@v10.0.3 sha256=7a13d79578e0a087 lines=164
OK npgsql-main-NpgsqlCommand-Dispose.txt npgsql/npgsql@main sha256=fe55e7bb660c4a51 lines=1632
OK npgsql-main-NpgsqlDataReader-Close-public.txt npgsql/npgsql@main sha256=8dfddffefbbb77c7 lines=1096
OK runtime-v8.0.20-DataTable-Load.txt dotnet/runtime@v8.0.20 sha256=469f053f148bd5e4 lines=4969
OK runtime-v10.0.12-DataTable-Load.txt dotnet/runtime@v10.0.12 sha256=dd4002e7407b1b15 lines=4974
OK runtime-v10.0.12-DbCommand-class.txt dotnet/runtime@v10.0.12 sha256=c8f6f56c13b82f05 lines=11
OK runtime-v10.0.12-DbCommand-DisposeAsync.txt dotnet/runtime@v10.0.12 sha256=c8f6f56c13b82f05 lines=245
OK runtime-v10.0.12-DbDataReader-Close-Dispose.txt dotnet/runtime@v10.0.12 sha256=c2f3c2871cbc269f lines=34
OK runtime-v10.0.12-IDbCommand.txt dotnet/runtime@v10.0.12 sha256=5fee96c4567d3894 lines=8
OK runtime-v8.0.20-Activity-Dispose.txt dotnet/runtime@v8.0.20 sha256=2fcfbffca75351dd lines=1006
OK runtime-v8.0.20-Activity-IDisposable.txt dotnet/runtime@v8.0.20 sha256=2fcfbffca75351dd lines=56
OK mssqlite-SqliteCommand-Dispose.txt dotnet/efcore@v10.0.12 sha256=c5d427a5d7016152 lines=216
OK mssqlite-SqliteCommand-DisposePreparedStatements.txt dotnet/efcore@v10.0.12 sha256=c5d427a5d7016152 lines=520
OK mssqlite-SqliteCommand-PrepareAndEnumerate-head.txt dotnet/efcore@v10.0.12 sha256=c5d427a5d7016152 lines=464
OK mssqlite-SqliteCommand-preparedStatements-field.txt dotnet/efcore@v10.0.12 sha256=c5d427a5d7016152 lines=30
OK mssqlite-SqliteDataReader-Close-Dispose.txt dotnet/efcore@v10.0.12 sha256=0712b68bd0b03688 lines=227
OK mssqlite-SqliteConnection-commands-weakrefs.txt dotnet/efcore@v10.0.12 sha256=0fd8dd0cd1ca7e6f lines=31
OK mssqlite-SqliteConnection-Handle.txt dotnet/efcore@v10.0.12 sha256=0fd8dd0cd1ca7e6f lines=129
OK efcore-v10.0.12-SQLitePCLRawVersion.txt dotnet/efcore@v10.0.12 sha256=a31b3e681cac5f15 lines=34
OK mssqlite-v10.0.12-Microsoft.Data.Sqlite-target.txt dotnet/efcore@v10.0.12 sha256=00448ec2082b4c14 lines=18
OK mssqlite-v10.0.12-Core-targets.txt dotnet/efcore@v10.0.12 sha256=b58e8f7587a04c49 lines=18
OK efcore-v10.0.12-default-net-target.txt dotnet/efcore@v10.0.12 sha256=a31b3e681cac5f15 lines=14
OK sqlitepclraw-v2.1.12-sqlite3_next_stmt.txt ericsink/SQLitePCL.raw@v2.1.12 sha256=cab23c3ea0012e85 lines=1028
OK sqlitepclraw-v2.1.12-enable-next-stmt.txt ericsink/SQLitePCL.raw@v2.1.12 sha256=9afd074db410ba78 lines=300
OK sqlitepclraw-v2.1.12-find-stmt-enabled.txt ericsink/SQLitePCL.raw@v2.1.12 sha256=9afd074db410ba78 lines=323
OK runtime-v8.0.20-SafeHandle-finalizer.txt dotnet/runtime@v8.0.20 sha256=3df9d6928d6a8bcb lines=86
OK runtime-v10.0.12-SafeHandle-finalizer.txt dotnet/runtime@v10.0.12 sha256=3df9d6928d6a8bcb lines=86
OK sqlitepclraw-sqlite3_stmt-SafeHandle.txt ericsink/SQLitePCL.raw@v2.1.12 sha256=9afd074db410ba78 lines=195
OK sqlclient-SqlCommand-Dispose.txt dotnet/SqlClient@main sha256=fc8200df4b130136 lines=1883
OK mysqlconnector-MySqlCommand-Dispose.txt mysql-net/MySqlConnector@master sha256=4369c492ce1c1fc1 lines=377
SCAN npgsql-10.0.3-NpgsqlCommand-finalizer-scan.txt npgsql/npgsql@v10.0.3 sha256=6bdde5901d32a633 matches=0
36 changes: 36 additions & 0 deletions corpus/ownership-lab/h28-command/evidence/ci-run-38048287923.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# H-28 mandatory GitHub Actions gate record
# Captured from gh run view / GitHub Actions API; this is status metadata, not the per-stage log.
run: https://github.com/PhysShell/Own.NET/actions/runs/38048287923
head: 008a21736e83139954d4ed1b34ab89fc8a194a00 (arena/e1a5511b-own-net; PR #399)
{
"conclusion": "success",
"databaseId": 38048287923,
"event": "pull_request",
"headSha": "008a21736e83139954d4ed1b34ab89fc8a194a00",
"jobs": [
{
"name": "H-28 required runtime + extractor gates",
"status": "completed",
"conclusion": "success",
"steps": [
{
"name": "Install self-contained PostgreSQL 16 harness",
"conclusion": "success"
},
{
"name": "Run mandatory G1-G3 gates (SKIP is failure)",
"conclusion": "success"
},
{
"name": "Preserve source facts and runtime observations",
"conclusion": "success"
}
]
}
],
"status": "completed",
"url": "https://github.com/PhysShell/Own.NET/actions/runs/38048287923"
}
artifact:
{"expired":false,"name":"h28-command-falsifier","size_in_bytes":6235}
note: raw run-log and artifact downloads redirect to the Actions results blob service; this sandbox cannot access that host.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# H-28-CMD source citation (auto-derived, do not edit by hand)
# repo : dotnet/efcore
# ref : v10.0.12
# path : eng/Versions.props
# blob sha : 4299bcff02df10cacebb45435c16cd0af9f901f3
# file sha256: a31b3e681cac5f1537ef29e7b81976b4f61533affd7c5857de3d19f469be7c6e
# file bytes : 2726
# marker : '<SQLitePCLRawVersion>'
# region : lines 34..37
# derived by: scripts/derive_source_evidence.py
34| <SQLitePCLRawVersion>2.1.12</SQLitePCLRawVersion>
35| <SQLitePCLRawBundleESqlcipherVersion>2.1.11</SQLitePCLRawBundleESqlcipherVersion>
36| <SQLitePCLRawBundleSqlite3Version>2.1.11</SQLitePCLRawBundleSqlite3Version>
37| <SQLitePCLRawBundleWinsqlite3Version>2.1.11</SQLitePCLRawBundleWinsqlite3Version>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# H-28-CMD source citation (auto-derived, do not edit by hand)
# repo : dotnet/efcore
# ref : v10.0.12
# path : eng/Versions.props
# blob sha : 4299bcff02df10cacebb45435c16cd0af9f901f3
# file sha256: a31b3e681cac5f1537ef29e7b81976b4f61533affd7c5857de3d19f469be7c6e
# file bytes : 2726
# marker : '<DefaultNetCoreTargetFramework>net10.0</DefaultNetCoreTargetFramework>'
# region : lines 14..17
# derived by: scripts/derive_source_evidence.py
14| <DefaultNetCoreTargetFramework>net10.0</DefaultNetCoreTargetFramework>
15| </PropertyGroup>
16| <PropertyGroup Label="Arcade settings">
17| <UsingToolXliff>False</UsingToolXliff>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
corpus/ownership-lab/h28-command/fx/CommandDispose.own:43:3: error: [OWN001] 'command' is owned but not released at end of function (leaks on at least one path) [resource: disposable]
43 | release reader; // DataTable.Load(reader) -> reader.Close()
^
note: 'command' acquired here at corpus/ownership-lab/h28-command/fx/CommandDispose.own:41
corpus/ownership-lab/h28-command/fx/CommandDispose.own:71:32: error: [OWN001] 'command' is owned but not released at end of function (leaks on at least one path) [resource: disposable]
71 | let reader = acquire Reader(command);
^
note: 'command' acquired here at corpus/ownership-lab/h28-command/fx/CommandDispose.own:70
corpus/ownership-lab/h28-command/fx/CommandDispose.own:71:7: error: [OWN001] 'reader' is owned but not released at end of function (leaks on at least one path) [resource: disposable]
71 | let reader = acquire Reader(command);
^
note: 'reader' acquired here at corpus/ownership-lab/h28-command/fx/CommandDispose.own:71

3 errors.
# exit code: 1 (OWN001 is error severity, so a finding run exits 1)
# command: python3 -m ownlang check corpus/ownership-lab/h28-command/fx/CommandDispose.own
# python: Python 3.11.2
Loading
Loading