""" Publication English rulebook: the rules every humanized sentence must satisfy before it can replace the author's sentence. One source of truth, used in two ways: * PROMPT - the rules as instructions for the language-model steps (quality check, final polish, alternatives), so the rewrite is written to the rules in the first place; * violations(original, rewrite) - the automatic checks of every rule that can be measured. The clarity gate (clarity.py) rejects a rewrite that breaks any of them; if no version of a sentence passes, the author's original sentence is kept. A sentence is therefore never made worse than the author wrote it. Rule groups A. Integrity (never broken) - meaning, claims, numbers, units, citations, terms, acronyms, negation, direction of every comparison, strength of every claim (hedging), one sentence in = one out B. Grammar - complete, correct sentences (checked by the grammar / fluency models in clarity.py) C. Academic register - formal, impersonal, no contractions, no "you", no first person singular, no informal words, no rhetorical questions, no exclamation marks D. Human academic style - no AI-typical vocabulary or stock phrases, no em dashes, no padding, plain specific verbs, varied rhythm, no sentence-initial "And/But/So/Also" E. Flow - logical links only where needed, no new paragraph-level claims F. Consistency - the author's spelling (British / American), terminology, tense and number format Space variables PUBRULES 1 (default) | 0 = automatic rule checks off (the prompt rules stay) PUB_MAX_WORDS default 40 a rewrite may not exceed this length unless the original already did """ import os import re import textparse as TP ENABLED = os.environ.get("PUBRULES", "1") != "0" MAX_WORDS = int(os.environ.get("PUB_MAX_WORDS", "40")) # ------------------------------------------------------------------------------------------------ word lists AI_WORDS = ["delve", "delves", "delving", "crucial", "pivotal", "comprehensive", "furthermore", "moreover", "notably", "additionally", "leverage", "leverages", "leveraging", "robust", "seamless", "seamlessly", "intricate", "landscape", "realm", "underscore", "underscores", "underscoring", "showcase", "showcases", "tapestry", "multifaceted", "paramount", "meticulous", "meticulously", "holistic", "foster", "fosters", "fostering", "testament", "ever-evolving", "groundbreaking", "cutting-edge", "game-changer", "revolutionize", "revolutionise", "unprecedented", "invaluable", "noteworthy", "commendable", "vibrant", "embark", "embarks", "unveil", "unveils", "harness", "harnesses", "harnessing", "navigate", "navigating", "elevate", "elevates", "streamline", "synergy", "synergistic", "nuanced", "myriad", "plethora", "endeavor", "endeavour", "bolster", "bolsters", "spearhead", "transformative", "unwavering", "intrinsically", "profound", "profoundly", "enhance", "enhances"] AI_PHRASES = [r"it is (?:important|worth|crucial|essential) to (?:note|mention|highlight|emphasi[sz]e)", r"plays? an? (?:crucial|pivotal|vital|key|significant|important) role", r"in today'?s (?:world|era|landscape|society|digital age)", r"a testament to", r"in the (?:realm|landscape|ever-evolving|rapidly evolving) (?:of )?", r"shed(?:s|ding)? light on", r"pav(?:e|es|ed|ing) the way", r"\bnot only\b.{1,80}\bbut also\b", r"at the end of the day", r"in conclusion,", r"to sum up", r"it can be (?:seen|said|argued) that", r"serves? as a", r"stands? as a", r"a wide (?:range|array|variety) of", r"the (?:intricate|complex) interplay", r"in order to", r"due to the fact that", r"with regard to", r"a (?:key|vital|crucial) aspect", r"rich (?:history|tapestry)", r"(?:navigate|navigating) the (?:complexities|challenges)"] _AI_PHRASE_RE = [re.compile(p, re.I) for p in AI_PHRASES] _AI_WORD_RE = re.compile(r"\b(" + "|".join(re.escape(w) for w in AI_WORDS) + r")\b", re.I) NEGATORS = r"\b(?:not|no|never|none|neither|nor|without|cannot|unable|fail(?:s|ed)? to|lack(?:s|ed|ing)?|absence)\b|n't\b" # ("indicate" is a neutral reporting verb, like "show": swapping the two does not change the strength of a claim) HEDGES = r"\b(?:may|might|could|can|suggests?|suggested|suggesting|impl(?:y|ies|ied|ying)|appears?|appeared|" \ r"seems?|seemed|likely|unlikely|possibly|potentially|probably|perhaps|presumably|apparently|arguably|" \ r"approximately|roughly|nearly|almost|partly|partially|somewhat|tends?|tended|tending|inclined|" \ r"relatively|generally|typically|usually|often)\b" BOOSTERS = r"\b(?:proves?|proved|proven|clearly|definitely|certainly|undoubtedly|always|completely|fully|" \ r"guarantees?|guaranteed|conclusively|obviously|absolutely|entirely|perfectly)\b" # a rewrite may not state a cause the author did not state CAUSAL = r"\b(?:because|since|therefore|thus|hence|consequently|thereby|as a result|due to|owing to|so that)\b" _WE = re.compile(r"\b(?:we|our|ours|us)\b", re.I) # direction words: a rewrite may not turn one into its opposite OPPOSITES = [("increas", "decreas"), ("higher", "lower"), ("more", "less"), ("more", "fewer"), ("rise", "fall"), ("rais", "lower"), ("improv", "degrad"), ("improv", "wors"), ("above", "below"), ("maxim", "minim"), ("positive", "negative"), ("significant", "insignificant"), ("significant", "non-significant"), ("accept", "reject"), ("before", "after"), ("includ", "exclud"), ("enabl", "disabl"), ("strengthen", "weaken"), ("larger", "smaller"), ("gain", "loss"), ("success", "failure"), ("outperform", "underperform"), ("strong", "weak"), ("faster", "slower"), ("best", "worst"), ("upper", "lower"), ("tamper-evident", "tampered"), ("halve", "double"), ("allow", "block"), ("allow", "prevent"), ("permit", "forbid"), ("grant", "revok"), ("inside", "outside"), ("honest", "dishonest"), ("trust", "distrust"), ("safe", "unsafe")] _INFORMAL_START = re.compile(r"^\s*(?:And|But|So|Also|Plus|Anyway|Well|Basically|Actually)\b") _EM_DASH = re.compile(r"\s[—–]\s|—") _CONTRACTION = re.compile(r"\b\w+(?:n't|'re|'ll|'ve|'m|'d)\b", re.I) _FIRST_SING = re.compile(r"\b(?:I|me|my|mine|myself)\b") _YOU = re.compile(r"\b(?:you|your|yours|yourself)\b", re.I) _UNITS = (r"(?:%|ms|µs|μs|ns|s|Hz|kHz|MHz|GHz|dB|dBm|nm|µm|μm|mm|cm|m|km|µg|μg|ng|mg|g|kg|µL|μL|mL|ml|L|mV|kV|V|µA|μA|mA|A|" r"mW|kW|MW|W|kWh|Wh|J|kJ|K|°C|°F|h|min|px|KB|MB|GB|TB|bps|Mbps|Gbps|Pa|kPa|MPa|GPa|bar|kN|mol|mmol|µmol|" r"μmol|rpm)(?:/[A-Za-zµμ]+\d?)?") _NUM = re.compile(rf"(?:(?<=[\s(])[-−+±])?(? 0) != (_count(NEGATORS, o) > 0) or abs(_count(NEGATORS, n) - _count(NEGATORS, o)) > 1: out.append("negation changed") ow, nw = _stems(o), _stems(n) for a, b in OPPOSITES: for x, y in ((a, b), (b, a)): if _has(nw, x) and not _has(ow, x) and _has(ow, y) and not _has(nw, y): out.append(f"direction reversed ({y}… → {x}…)") break if _count(HEDGES, o) and not _count(HEDGES, n): out.append("hedging removed (claim made stronger)") if _count(BOOSTERS, n) > _count(BOOSTERS, o): out.append("claim made stronger") if _count(CAUSAL, n) and not _count(CAUSAL, o): # "X mediates Y, suggesting Z" is not "because X, Z" out.append("causal link added") if _WE.search(n) and not _WE.search(o): # "we surveyed": a voice (and often a method) not the author's out.append("first person plural added") if len(TP.split_sentences(n)) != len(TP.split_sentences(o)): # one sentence in = one sentence out out.append("sentence split or merged") import profile_settings as PS if PS.get("rules") == "integrity": # priority "ai": integrity rules only return out # ---- C. academic register for pat, why in ((_CONTRACTION, "contraction"), (_FIRST_SING, "first person singular"), (_YOU, "addresses the reader")): if pat.search(n) and not pat.search(o): out.append(why) if "!" in n and "!" not in o: out.append("exclamation mark") # ---- D. human academic style added = {m.group(0).lower() for m in _AI_WORD_RE.finditer(n)} - {m.group(0).lower() for m in _AI_WORD_RE.finditer(o)} if added: out.append("AI-typical word: " + ", ".join(sorted(added))) for rx in _AI_PHRASE_RE: if rx.search(n) and not rx.search(o): out.append("AI-typical phrase") break if _EM_DASH.search(n) and not _EM_DASH.search(o): out.append("em dash") if _INFORMAL_START.search(n) and not _INFORMAL_START.search(o): out.append("sentence starts with a conjunction") if len(n.split()) > max(MAX_WORDS, len(o.split()) + 5): out.append("sentence too long") # ---- F. consistency po, pr_o = len(_PAST_AUX.findall(o)), len(_PRES_AUX.findall(o)) pn, pr_n = len(_PAST_AUX.findall(n)), len(_PRES_AUX.findall(n)) if (po and not pr_o and pr_n and not pn) or (pr_o and not po and pn and not pr_n): out.append("tense changed") return out # ------------------------------------------------------------------------------------------------ prompt rules PROMPT = f"""PUBLICATION ENGLISH RULES (every sentence you return must satisfy all of them): A. Integrity - never broken: A1. Same meaning, same claims, same scope. Add nothing (no new facts, examples, causes, names, numbers, results). Drop nothing (every clause, condition, qualifier and list item stays). A2. Every number, unit, statistic (β, p, r, R², %, n, CI), variable, symbol, equation reference, technical term, acronym, model or dataset name, author name, year and citation ([12], (Kumar et al., 2021)) stays exactly as written and stays attached to the same claim. Never move, merge, renumber or duplicate a citation. A3. Never reverse a direction or a polarity: higher/lower, increase/decrease, before/after, allow/block, with/ without, not/no stay as they are. "tamper-evident" never becomes "can be tampered with". A4. Keep the strength of every claim: keep may/might/suggests/approximately; never add proves/clearly/always/all. A5. One sentence in, one sentence out: never split, merge, drop or reorder sentences. A6. Never replace a technical term with a synonym ("accuracy" is not "precision", "sweeps" is not "reaches", "escalates" is not "increases"); when unsure, keep the author's word. The study's own constructs (every term defined with an abbreviation, e.g. "travel satisfaction (TS)", "intimacy (IN)") keep their exact names: never "pleasure", "contentment", "happiness", "closeness", "allegiance", "devotion" for them. A7. Never add a reason, cause, explanation or attribution the original does not state ("according to some experts", "since they have ...", "a systematic analysis found", "researchers contend"). A8. Keep every list item and every name or place ("Digha, Darjeeling, Jhargram and Purulia" keeps all four). A9. Keep statistics exactly: "p = .120" stays "p = .120"; never turn "=" into "<" or ">", never add an operator that is missing in the original, never drop one ("p < .001" never becomes "p .001"). A10. Never end a sentence or a term half-way ("... and to enhance their.", "well-,"). B. Grammar - every sentence complete and correct: subject-verb agreement, articles, verb forms, tense, prepositions, punctuation (keep every comma of the original that is still needed: in lists, after introductory phrases such as "After COVID-19," or "However,", and after a bracketed abbreviation in a list; never remove commas to change the style), no missing, doubled or run-together words, no fragments, no run-on sentences, a capital only where English needs one ("Greshake et al. generalised", not "et al. Generalised"). C. Academic register: formal and impersonal; no contractions, no "you", no first person singular, no informal or conversational words, no rhetorical questions, no exclamation marks; "we" only where the author used it. D. Human academic style (how careful researchers actually write): D1. Plain, specific verbs (shows, reduces, uses, compares) instead of inflated ones. D2. Never use: {", ".join(AI_WORDS[:40])}; never use stock phrases such as "it is important to note", "plays a crucial role", "in today's world", "a testament to", "sheds light on", "paves the way", "not only ... but also", "a wide range of", "in order to", "due to the fact that", "serves as". D3. No em dashes, no lists of three adjectives, no padding, no summary sentences that repeat the previous one. D4. Vary rhythm naturally (a shorter direct sentence after a long one is good); never above {MAX_WORDS} words unless the original sentence already was; never start with And, But, So or Also. E. Flow: each sentence follows logically from the previous one; add a linking word (however, therefore, in contrast, for example) only where the logic needs it; never add a new claim to make text flow. F. Consistency: keep the author's spelling (British or American), terminology, tense and number format throughout; the same concept always has the same name."""