Skip to content

ruff_python_spo: residual ledger for the plain arm — silent skips become named, addressed rows - #96

Merged
AdaWorldAPI merged 1 commit into
mainfrom
claude/plain-spo-residual-ledger
Aug 18, 2026
Merged

ruff_python_spo: residual ledger for the plain arm — silent skips become named, addressed rows#96
AdaWorldAPI merged 1 commit into
mainfrom
claude/plain-spo-residual-ledger

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

Summary

First increment of the self-adaptive drill loop over the plain-Python arm (#95): before any proposer can turn residue into data-as-config rows, the residue has to exist as data. The plain arm's declared gaps — module-level constants invisible, nested classes unwalked, complex annotations unresolved, non-literal assigns dropped, unresolvable bases dropped, unparsable files silent — were all silent skips. This PR makes each one a PlainResidual row: a named reason (closed enum, no catch-all — the intake-arm slag doctrine), a module + class + name address, and a reason-specific detail.

Strictly additive: extract_plain_from_source_with_residuals / extract_plain_with_residuals return (ModelGraph, Vec<PlainResidual>); the existing entry points delegate and drop the ledger. A dedicated test pins that the graph half is identical between the two paths on a fixture exercising every residual reason at once — observation, never behaviour change.

The CURIE channel enters as measurement, not harvest

A module- or class-level string constant whose value is CURIE-shaped (PREFIX:localid) gets a curie_constant row carrying the prefix only. The local id is opaque by design: OBO locals and SNOMED sctids alike carry no structure in the identifier — hierarchy for such vocabularies lives in the ontology's edges (the terminology horseshoe), so drilling past the prefix is the resolution target's job, never string parsing. The shape check is two-sided and tested: URLs (rest starts /), Windows paths (backslash), clock times (digit prefix), and spaced strings all stay module_constant.

Measured — three corpora + one adversarial

corpus rows dominant reasons curie
dismech (84 files) 1,452 non_name_assign_target 493 · non_literal_assign 455 (451 = call) · module_constant 386 · unresolved_annotation 96 (all binop unions) 22 rows, 12 prefixes: KISAO 4, infores 3, MONDO/dismech/linkml/sqlite/xsd 2, Monarch/RO/biolink/rdfs… 1
A2UI sdk (127 files) 299 module_constant 239 0
ruff/scripts (23 files) 67 module_constant 45 · unresolved_annotation 12 0
ruff_linter fixtures (1,586 deliberately-malformed files) 3,786 exit 0; unparsable_source 9

Three readings:

  1. The histogram concentrates — 2–3 reasons dominate per corpus. There is something to drill toward; the loop deserves its next increment (a proposer that emits candidate config rows from the dominant buckets, gated by an exact-count coverage check).
  2. curie_constant fires exactly where ontology work lives (dismech) and is silent on both non-ontology corpora — the can-fire / can-stay-silent pair, measured at corpus scale rather than only in unit fixtures.
  3. sqlite: among the prefixes is the design argument in one row: a connection-string URI is CURIE-shaped but not an ontology reference, so prefix→codebook-target binding must be a config decision a measurement gate ratifies, never an auto-lift.

Falsifier discipline

Every new test asserts exact counts (==). Each residual-recording site was verified by a disable run — mutation anchor asserted to exist, test observed red, restored, full suite green: the slash exclusion (URL test goes red), the class-level CURIE recording (class-level curie row panic), and the module-constant recording. One first-attempt mutation failed to compile and thereby verified nothing — caught because the filtered run's output was empty rather than red, redone with a compiling mutation before being counted.

Test plan

  • cargo test -p ruff_python_spo70/70 (66 pre-existing + 4 new)
  • cargo clippy -p ruff_python_spo --all-targets -- -D warnings — clean (one doc_markdown fixed en route)
  • cargo fmt + RUSTDOCFLAGS="-D warnings" cargo doc --no-deps -p ruff_python_spo — clean (the R2IL intake arm: plan, implementation spec, and ruff_r2il crate (PR 1) #94 gate holds over the new surface)
  • uvx prek run --from-ref main --to-ref HEAD — all hooks pass, git status clean after (no fixer rewrote anything)
  • Census reproduced over all four corpora above; adversarial corpus exits 0

Generated by Claude Code

…ssed row

First increment of the self-adaptive drill loop: before a proposer can turn
residue into config rows, the residue has to exist as data. The plain arm's
declared gaps (module doc: module-level constants invisible, nested classes
unwalked, complex annotations unresolved, non-literal assigns dropped,
unresolvable bases dropped, unparsable files silent) were all SILENT skips.
This makes each one a PlainResidual row - named reason (closed enum, no
catch-all), module + class + name address, and a reason-specific detail.

New API, strictly additive: extract_plain_from_source_with_residuals /
extract_plain_with_residuals return (ModelGraph, Vec<PlainResidual>); the
existing entry points delegate and drop the ledger. A dedicated test pins
that the graph half is byte-identical between the two paths on a fixture
exercising every residual reason at once.

The CURIE channel enters as MEASUREMENT, not harvest: a module-level or
class-level string constant whose value is CURIE-shaped (PREFIX:localid)
gets a curie_constant row carrying the PREFIX ONLY. The local id is opaque
by design - OBO locals and SNOMED sctids alike carry no structure in the
identifier; hierarchy for such vocabularies lives in the ontology's edges,
so drilling past the prefix is the resolution target's job, never string
parsing. The shape check is two-sided and tested: URLs (rest starts with
/), Windows paths (backslash), clock times (digit prefix), and spaced
strings all stay module_constant.

plain_census now prints the residual histogram (by reason, top details).
Measured over three corpora + one adversarial:

  dismech (84 files):   1452 rows - non_name_assign_target 493,
    non_literal_assign 455 (451 of them =call), module_constant 386,
    unresolved_annotation 96 (all binop unions), curie_constant 22
    across 12 prefixes: KISAO 4, infores 3, MONDO/dismech/linkml/
    sqlite/xsd 2 each, Monarch/RO/biolink/rdfs/... 1 each
  A2UI sdk (127 files):  299 rows - module_constant 239; curie 0
  ruff/scripts (23):      67 rows - module_constant 45; curie 0
  ruff_linter fixtures (adversarial, 1586 deliberately-malformed
    files): exit 0, 3786 rows, unparsable_source 9 - the silent-skip
    invariant holds at scale and the parse-failure path is measured.

Three readings off those numbers: (1) the histogram CONCENTRATES - 2-3
reasons dominate per corpus, so there is something to drill toward; (2)
curie_constant fires exactly where ontology work lives (dismech) and is
silent on both non-ontology corpora - the can-fire/can-stay-silent pair
at corpus scale; (3) sqlite: appearing among the prefixes proves prefix
binding must be a CONFIG decision, not an auto-lift - a connection-string
URI is CURIE-shaped but not an ontology reference, so the prefix->target
binding belongs in a data-as-config row a measurement gate ratifies.

Every new test asserts exact counts, and each residual-recording site was
verified by a disable run (mutation asserted to exist, test observed red,
restored, full suite green): the slash exclusion, the class-level CURIE
recording, and the module-constant recording each have a test that fails
when that specific code path is unhooked. One first-attempt mutation
failed to compile and thereby verified nothing - redone with a compiling
mutation before being counted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGVLyRZNEKKBSfBDJfbY3V
@cursor

cursor Bot commented Aug 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_7a579ae2-70eb-4ca7-92d5-b9c1e25921e2)

@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review August 18, 2026 05:47
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@AdaWorldAPI
AdaWorldAPI merged commit cac0f1a into main Aug 18, 2026
28 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants