route_plan: fix Python-comment-in-f-string regression in translation_chain
Live re-run after the c995bc2 Device-DN fix returned "A syntax error has occurred" from Informix. Cause: the explanatory comment block documenting why tkpatternusage=2 was added landed *inside* the translation_chain f-string instead of above it. Python's `#` line comments only work outside string literals — inside an f-string, each `#` is literal text. Informix received SQL with `#` lines after the JOIN clauses, parsed them as illegal tokens, and rejected. Offline tests didn't catch this because the FakeAxlClient dispatches on substring matches without actually parsing the SQL. The bug only manifested when the SQL hit a real Informix engine. Fix: move the comment block ABOVE the `sql = f"""` assignment so it becomes a real Python comment instead of literal SQL text. Sentinel test added (test_no_python_comment_chars_leak_into_sql): captures all SQL emitted by a cti_failsafe_reachability call and asserts no `#` character appears anywhere. CUCM's data dictionary doesn't use `#` in any table or column name, and Informix uses `--` / `/* */` for comments — so a `#` in any captured query is almost certainly an escaped Python comment. Catches this exact class of regression for any future contributor. Tests: cti suite 33 → 34; full mcaxl suite 271 → 272 passing. Operational impact: this regression made cti_failsafe_reachability unrunnable against any live cluster between c995bc2 and this fix. The Bingham 6→4 finding-reduction verification queued in 008 is unblocked once the MCP server reloads with this commit.
This commit is contained in:
parent
c995bc2712
commit
1b92f83dc4
@ -1734,22 +1734,7 @@ def translation_chain(client: "AxlClient", number: str, css_name: str | None = N
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Pull every pattern in scope; we filter in Python with wildcard logic.
|
# Pull every pattern in scope; we filter in Python with wildcard logic.
|
||||||
sql = f"""
|
#
|
||||||
SELECT
|
|
||||||
np.dnorpattern AS pattern,
|
|
||||||
tpu.name AS pattern_type,
|
|
||||||
rp.name AS partition_name,
|
|
||||||
np.callingpartytransformationmask AS calling_party_xform_mask,
|
|
||||||
np.calledpartytransformationmask AS called_party_xform_mask,
|
|
||||||
np.prefixdigitsout AS prefix_digits_out,
|
|
||||||
ddi.name AS digit_discard_instructions,
|
|
||||||
rf.name AS route_filter,
|
|
||||||
np.description AS description
|
|
||||||
FROM numplan np
|
|
||||||
LEFT OUTER JOIN routepartition rp ON np.fkroutepartition = rp.pkid
|
|
||||||
LEFT OUTER JOIN typepatternusage tpu ON np.tkpatternusage = tpu.enum
|
|
||||||
LEFT OUTER JOIN digitdiscardinstruction ddi ON np.fkdigitdiscardinstruction = ddi.pkid
|
|
||||||
LEFT OUTER JOIN routefilter rf ON np.fkroutefilter = rf.pkid
|
|
||||||
# tkpatternusage candidates included in the match scan:
|
# tkpatternusage candidates included in the match scan:
|
||||||
# 2 = Device (DN) — directly-dialable directory numbers
|
# 2 = Device (DN) — directly-dialable directory numbers
|
||||||
# 3 = Translation — translation patterns
|
# 3 = Translation — translation patterns
|
||||||
@ -1766,6 +1751,22 @@ def translation_chain(client: "AxlClient", number: str, css_name: str | None = N
|
|||||||
# was the cause of the false-positive: candidates_evaluated stayed
|
# was the cause of the false-positive: candidates_evaluated stayed
|
||||||
# 23 vs 26 numplan rows in the reachable partition, with the 3-row
|
# 23 vs 26 numplan rows in the reachable partition, with the 3-row
|
||||||
# gap being exactly the 3 Device DNs.
|
# gap being exactly the 3 Device DNs.
|
||||||
|
sql = f"""
|
||||||
|
SELECT
|
||||||
|
np.dnorpattern AS pattern,
|
||||||
|
tpu.name AS pattern_type,
|
||||||
|
rp.name AS partition_name,
|
||||||
|
np.callingpartytransformationmask AS calling_party_xform_mask,
|
||||||
|
np.calledpartytransformationmask AS called_party_xform_mask,
|
||||||
|
np.prefixdigitsout AS prefix_digits_out,
|
||||||
|
ddi.name AS digit_discard_instructions,
|
||||||
|
rf.name AS route_filter,
|
||||||
|
np.description AS description
|
||||||
|
FROM numplan np
|
||||||
|
LEFT OUTER JOIN routepartition rp ON np.fkroutepartition = rp.pkid
|
||||||
|
LEFT OUTER JOIN typepatternusage tpu ON np.tkpatternusage = tpu.enum
|
||||||
|
LEFT OUTER JOIN digitdiscardinstruction ddi ON np.fkdigitdiscardinstruction = ddi.pkid
|
||||||
|
LEFT OUTER JOIN routefilter rf ON np.fkroutefilter = rf.pkid
|
||||||
WHERE np.tkpatternusage IN (2, 3, 5, 7)
|
WHERE np.tkpatternusage IN (2, 3, 5, 7)
|
||||||
AND np.dnorpattern IS NOT NULL
|
AND np.dnorpattern IS NOT NULL
|
||||||
{css_filter}
|
{css_filter}
|
||||||
|
|||||||
@ -466,6 +466,39 @@ class TestDeviceDnInTranslationChainCandidates:
|
|||||||
"empirical proof."
|
"empirical proof."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_no_python_comment_chars_leak_into_sql(self):
|
||||||
|
"""Sentinel — a `#` in any captured query is almost certainly a
|
||||||
|
Python comment that escaped its f-string. Informix doesn't use
|
||||||
|
`#` for comments (it uses `--` and `/* */`); CUCM's data
|
||||||
|
dictionary doesn't use `#` in table or column names either.
|
||||||
|
|
||||||
|
Caught a real regression in 2026-05-09 cti-audit-prompts
|
||||||
|
thread: a Python explanatory comment was placed *inside* the
|
||||||
|
translation_chain f-string (after the JOIN clauses, before
|
||||||
|
WHERE). Informix returned "A syntax error has occurred" on
|
||||||
|
every live call. Offline tests passed because the FakeAxlClient
|
||||||
|
dispatched on substring matches and didn't parse the SQL.
|
||||||
|
|
||||||
|
This test wouldn't have caught the original bug if it predated
|
||||||
|
the fix (the FakeAxlClient still wouldn't fail) — but adding
|
||||||
|
it now means a future contributor can't reintroduce the same
|
||||||
|
class of mistake in any cti_failsafe_reachability call path.
|
||||||
|
"""
|
||||||
|
client = FakeAxlClient(cti_rp_rows=[
|
||||||
|
_cti_row("Test-RP", "Generic", cfna="912", cfna_css="SomeCSS"),
|
||||||
|
])
|
||||||
|
cti_failsafe_reachability(client)
|
||||||
|
for q in client.queries:
|
||||||
|
# Allow `#` in column-comment-like positions in SELECT lists?
|
||||||
|
# No — CUCM's data dictionary has no such columns. A `#`
|
||||||
|
# anywhere in any query my tool emits is a defect.
|
||||||
|
assert "#" not in q, (
|
||||||
|
f"Python `#` character leaked into SQL — likely a Python "
|
||||||
|
f"comment inside an f-string. Informix will reject this "
|
||||||
|
f"with 'A syntax error has occurred'. Offending query:\n"
|
||||||
|
f"{q[:200]}..."
|
||||||
|
)
|
||||||
|
|
||||||
def test_cti_rp_to_cti_rp_failsafe_does_not_false_positive(self):
|
def test_cti_rp_to_cti_rp_failsafe_does_not_false_positive(self):
|
||||||
"""The motivating Bingham case: 911-CTI-RP CFNA → 912 (Device DN
|
"""The motivating Bingham case: 911-CTI-RP CFNA → 912 (Device DN
|
||||||
of 912-CTI-RP) under 911CER-CSS reaching 911CER-PT.
|
of 912-CTI-RP) under 911CER-CSS reaching 911CER-PT.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user