From 713bc5dcf489a84a77c500a9749c47d515fceefd Mon Sep 17 00:00:00 2001 From: skishchampi <996985+skishchampi@users.noreply.github.com> Date: Thu, 20 Aug 2026 20:28:49 -0400 Subject: [PATCH] fix: FEDERAL_DEFLECTION could not see the participial state-subject form REQ-0072, filed by zero-hour. The pattern required a copula: \b(?:is|are)\s+(?:a|an)\s+[Ss]tate\s+[Ss]ubject\b Indian legislative English drops it. "Agriculture being a State subject, there is no investment in agriculture directly by the Central Government in the States" matched nothing. The pattern now accepts `being`. It is one alternation. Measured by zero-hour over 489,469 answered records. 3,080 answers use the participle, 2,982 of those match no copula, and 518 carry no label from any tier at all. THIS MOVES A PUBLISHED NUMBER. Re-run `analyse-discourse` on any corpus, then re-read every evasion rate computed from it. Two kinds of record move, and only the first is pure recall. The 518 unlabelled records gain the label, which raises both the evasive count and the classified denominator. The other 2,464 already carry a label from another pattern, and FEDERAL_DEFLECTION's 0.92 outranks it. That precedence is not introduced here. The copula form already outranks ACCEPTED and REJECTED today at the same confidence. This makes the participle behave exactly as the copula does. Whether a state-subject clause should outrank a substantive disclosure is a separate question, and it applies to the shipped copula pattern first. Three tests cover it. One carries the verbatim sentence with its source key. One guards that the two forms agree on label and confidence. One checks that copula matches do not move. --- CHANGELOG.md | 27 ++++++++++++++++++++ commoner_analyse/discourse.py | 9 +++++-- tests/test_discourse.py | 48 +++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3107c1f..a3c254a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,33 @@ researchers who pin a tag and want to know what they are pinning to. ## [Unreleased] +### Fixed + +- **This moves a published number, in one direction. Re-run + `analyse-discourse` on any corpus, then re-read every evasion rate computed + from it.** `FEDERAL_DEFLECTION`'s state-subject pattern required a copula: + `\b(?:is|are)\s+(?:a|an)\s+[Ss]tate\s+[Ss]ubject\b`. Indian legislative + English drops it. "Agriculture **being** a State subject, there is no + investment..." matched nothing. The pattern now accepts `being`. + + **Measured by zero-hour over 489,469 answered records (REQ-0072):** 34,632 + answers mention "State subject", 5,542 match the shipped copula pattern, and + 3,080 use the participle. Of those, 2,982 match no copula, and **518 carry no + label from any tier at all**. + + **Two kinds of record move, and only the first is pure recall.** The 518 + unlabelled records gain `FEDERAL_DEFLECTION`, which raises both the evasive + count and the classified denominator. The other 2,464 already carry a label + from some other pattern, and `FEDERAL_DEFLECTION`'s 0.92 confidence outranks + it. Where that old label was substantive, the evasion rate rises a second + time. Where it was evasive, only the label distribution changes. + + **That precedence is not new and is not introduced here.** The copula form + already outranks `ACCEPTED` and `REJECTED` today at the same confidence. The + alternation makes the participle behave exactly as the copula does. Whether + a state-subject clause should outrank a substantive disclosure is a separate + question, and it applies to the shipped copula pattern first. + ## [2.7.0] — 2026-08-20 ### Changed diff --git a/commoner_analyse/discourse.py b/commoner_analyse/discourse.py index 728245d..879d006 100644 --- a/commoner_analyse/discourse.py +++ b/commoner_analyse/discourse.py @@ -122,8 +122,13 @@ def _compile(patterns: Iterable[str]) -> tuple[re.Pattern, ...]: "Uses federalism/State Subjects to dodge Central responsibility for national standards.", _compile([ r"library\s+is\s+a\s+state\s+subject", - # Broader state-subject dodge pattern (mined from Azad corpus UNCLASSIFIED) - r"\b(?:is|are)\s+(?:a|an)\s+[Ss]tate\s+[Ss]ubject\b", + # Broader state-subject dodge pattern (mined from Azad corpus UNCLASSIFIED). + # `being` is not optional decoration. Indian legislative English drops the + # copula in this exact construction, and the participial form carries the + # same federal dodge: "Agriculture being a State subject, ...". Measured + # over 489,469 answered records, 2,982 use the participle and match no + # copula, and 518 of those carry no label from any tier (REQ-0072). + r"\b(?:is|are|being)\s+(?:a|an)\s+[Ss]tate\s+[Ss]ubject\b", r"\b(?:Concurrent|[Cc]oncurrent)\s+[Ll]ist\b", r"\bunder\s+entry\s+\d+\s+of\s+the\s+[Ss]tate\s+List\b", r"\bSeventh\s+Schedule\b", diff --git a/tests/test_discourse.py b/tests/test_discourse.py index 56c03d0..109e5e2 100644 --- a/tests/test_discourse.py +++ b/tests/test_discourse.py @@ -407,6 +407,54 @@ def test_state_subject_fires_federal_deflection(self): ) self.assertEqual(result.label, "FEDERAL_DEFLECTION") + def test_participial_state_subject_fires_federal_deflection(self): + """REQ-0072. Indian legislative English drops the copula in this exact + construction, and the pattern required it. Verbatim from the request, + source key ``LS|S|734|2000-05-17``, Minister of Agriculture. zero-hour + measured 2,982 answers using this form and invisible to the pattern, + of which 518 carried no label from any tier at all. + """ + from commoner_analyse.discourse import CHANNEL_QA + result = classify_response( + "Agriculture being a State subject, there is no investment in " + "agriculture directly by the Central Government in the States.", + channel=CHANNEL_QA, + ) + self.assertEqual(result.label, "FEDERAL_DEFLECTION") + + def test_the_participle_and_the_copula_agree(self): + """The alternation adds recall. It does not create a second behaviour. + + The two forms make the same claim, so they must reach the same label at + the same confidence. A drift between them is the defect returning. + """ + from commoner_analyse.discourse import CHANNEL_QA + pairs = [ + ("Agriculture is a State subject, so the Centre does not intervene.", + "Agriculture being a State subject, the Centre does not intervene."), + ("Health is a State subject and States decide.", + "Health being a State subject, States decide."), + ] + for copula, participle in pairs: + with self.subTest(participle=participle): + first = classify_response(copula, channel=CHANNEL_QA) + second = classify_response(participle, channel=CHANNEL_QA) + self.assertEqual(first.label, second.label) + self.assertEqual(first.confidence, second.confidence) + + def test_the_copula_form_still_matches(self): + """Acceptance 3. The alternation must not move a copula match.""" + from commoner_analyse.discourse import CHANNEL_QA + for text in ( + "Land is a state subject under the Seventh Schedule.", + "These are a State subject and rest with the States.", + ): + with self.subTest(text=text): + self.assertEqual( + classify_response(text, channel=CHANNEL_QA).label, + "FEDERAL_DEFLECTION", + ) + def test_concurrent_list_fires_federal_deflection(self): from commoner_analyse.discourse import CHANNEL_QA result = classify_response(