Repository navigation
Commit e524972
docs(h28): resolve the DbCommand residual — H28-PROVIDER-SPECIFIC
H-28 (research/ownership-semantics-lab-v1 @ 298b305, not on main) settled
DataTable.Load(reader) with a runtime falsifier: the reader IS closed, so the
presumed BORROW was refuted and the demanding instance
(victor-wiki/DatabaseManager DbInterpreter.GetDataTableAsync:699) is not a
protocol leak. The same record then wrote one sentence and never classified it:
"what remains is the never-disposed DbCommand `cmd` (an object leak without
a protocol consequence)"
That sentence is a description, not a verdict: it was never falsified, never
entered the witnessed-callee table, never reached a gate. This closes it.
VERDICT: H28-PROVIDER-SPECIFIC. The absence of DbCommand.Dispose() in this
family is not one fact.
* Npgsql 10.0.3 (and main, identical): NpgsqlCommand has no finalizer, both
ctors GC.SuppressFinalize, and Dispose(bool) only nulls _transaction, sets
a managed state flag and optionally recycles the command into the
connection's one-slot CachedCommand. Reset() is managed-only. Server-side
prepared statements belong to NpgsqlConnector.PreparedStatementManager and
are never DEALLOCATEd by the command. => releases nothing.
* Microsoft.Data.SqlClient, MySqlConnector: managed-only Dispose, no
finalizer. => releases nothing.
* Microsoft.Data.Sqlite: SqliteCommand.Dispose -> DisposePreparedStatements
finalizes native sqlite3_stmt SafeHandles (ReleaseHandle ->
sqlite3_finalize) AND disposes its reader. A plain ExecuteReader() runs
PrepareAndEnumerateStatements(), which puts those handles on the COMMAND;
SqliteDataReader.Close()/Dispose() does not finalize them. => the command
is the only deterministic releaser. REAL defect.
So the old residual is true for Npgsql and false for Microsoft.Data.Sqlite; it
was written from a two-provider falsifier whose SQLite arm never looked at the
command.
Sharper witness found on the way (pivot recorded in the report): the ownership
relation connection -> command -> reader is not what either side assumes.
NpgsqlCommand.CurrentActivity (System.Diagnostics.Activity IS IDisposable in
.NET 8 and 10) is stopped by exactly two call sites repo-wide, both in
NpgsqlDataReader.Dispose/DisposeAsync -> Command.TraceCommandStop(). Neither
NpgsqlDataReader.Close() nor NpgsqlCommand.Dispose() calls it — and
DataTable.Load calls Close(). With a tracing listener attached the span never
ends. Meanwhile reader Cleanup sets Command.State = Idle, which makes the
command reusable: that is not ownership.
CURRENT OWN.NET (extractor @ e889f8b, source-derived; engine executed):
IsOwningFactory mints an owned local for IDbConnection.CreateCommand()
(L4880-4882 -> L7035), IsDisposeOptional does not cover DbCommand (L2593), and
the argument-escape rule untracks the reader at table.Load(reader)
(L7155-7182). Predicted: OWN001 (error) on `command`, silence on `reader`. The
engine half reproduces exactly that (evidence/engine-CommandDispose.txt: 2x
command in B/E + 1x reader in E, A/D clean). On Npgsql with tracing on the
verdict is inverted — error on the object whose Dispose frees nothing, silence
on the one whose disposal is load-bearing.
The escape drop is also only accidentally right: DataTable.Load closes the
reader IFF !reader.NextResult(), so a multi-result-set reader is left OPEN and
the drop is a false negative there.
NO PRODUCTION CHANGE. Nothing here touches the extractor, the core, the
vocabulary or a diagnostic. corpus/ownership-lab/ is not globbed by
tests/test_corpus.py (still 33/33). The model gap is shown to be an instance of
#382 — which already names this lowering and this exact loss — with proven_call
(OwnIR v2, H1) as the landed transport precedent; section 10 proposes the
smallest experiment and explicitly not a lattice, a new code, or provider
special-casing.
Deliverables: docs/notes/h28-npgsql-command-resolution.md plus
corpus/ownership-lab/h28-command/ — fx/CommandDispose.cs (9 variants, abstract
ADO.NET types on purpose: that is what IsOwningFactory matches), a runnable
falsifier pinned to net8.0/Npgsql 10.0.3/MS.Data.Sqlite 10.0.12 with probes
P1-P6 each chosen to separate two hypotheses, and 32 source citations
auto-derived from pinned refs (blob sha + sha256 + line range) by
scripts/derive_source_evidence.py, which exits non-zero when the note goes stale.
Honest limits, stated in the report rather than papered over: there is no .NET
SDK and no reachable NuGet feed in the producing sandbox, so the Roslyn
extractor and the runtime falsifier were NOT executed. fx/CommandDispose.cs
expectations and probes P2/P4/P6 are marked PREDICTED; run.sh runtime prints
SKIP-WHY instead of faking it. What WAS executed: the engine half, all 32
source derivations, and a live PostgreSQL 16.2 (pgserver) used to pin that
prepared statements and cursors are session-scoped — independently corroborating
that no command-level Dispose can be their releaser.
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>1 parent e889f8b commit e524972
42 files changed
Lines changed: 2262 additions & 0 deletions
File tree
- corpus/ownership-lab/h28-command
- evidence
- falsifier
- fx
- scripts
- docs/notes
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
0 commit comments