CI test integrity batch 181A: controls that can fail, RE-DERIVE escalation, cp1252 roots, tests mypy ratchet (BACKLOG #1971, #1842, #1866, #1030, #1799) - #1825
Conversation
…1030) Brings messagefoundry_webconsole/, packaging/, samples/, tee/, fuzz/, docker/ and docs/ into the reach gate as parametrized rows, and folds the engine's three hand-written wrapper tests into the same rows. fuzz/ was not named in the ledger's list of six; a tracked-file census found it. All seven measured zero console-bound hits, so no source file changes. A planted U+2192 in one real file per new root turned all seven gate rows red, and a new per-root control plants the glyph in each pinned file's real text to prove every zero is the detector looking. Each row now pins a top-level and a nested file wherever the root has both shapes, and the coverage test checks that it does.
…#1799) scripts/ci/mypy_ratchet_check.py re-runs mypy over the ignore_errors list with the exemption flipped off, on linux and win32, and fails on a module clean on both. A ci.yml step runs it after the tests mypy pass. tests/test_mypy_tests_scope.py pins the step and plants a clean and a dirty module against the parser and verdict. Live control: planting tests.test_mypy_tests_scope on the list made the script exit 1 naming it.
Every surface in the cp1252 gate now walks `git ls-files` output through one cached helper, `_files_under(root, suffix)`. The scripts .py walk, the scripts .ps1 walk and the reach walk were three separate rglob expressions. A filesystem walk also read untracked scratch and build output, so two checkouts of one commit could disagree. The full list is read once and filtered in Python, never through a `<root>/**/*.py` pathspec, which drops top-level files. A git failure raises rather than returning an empty list. New census test: every top-level directory holding a tracked .py file must be a reach row or scripts/. Removing the fuzz/ row makes it fire.
…it can fail (BACKLOG #1971) test_ad_login_conflicting_with_local_account_is_rejected posted /auth/login with provider="ad". Directory password sign-in is retired, so _dispatch_login refused it before any directory work and the conflict branch in _complete_ad_login was never reached. The test now drives POST /auth/negotiate (Windows SSO), a live leg into _complete_ad_login. It asserts the 401, that the directory was consulted, exactly one auth.login_failed row with reason local_account_conflict, no success row, and the local account unchanged. The dead provider parameter on the _login helper is gone. Mutation: with the conflict branch disabled the test goes red. A later check still refuses as directory_identity_conflict, so only the audit reason catches it. The old test stayed green under the same mutation. Proposed PR title: test(auth): the AD local-account conflict test can fail again (BACKLOG #1971) Proposed ledger banner: SHIPPED -- the M4 conflict test drives Windows SSO into _complete_ad_login and pins the local_account_conflict audit row; red with the branch removed.
Closes the first of #1030's two named detector gaps. The reach detector saw only print, std-stream writes and loggers, so a non-cp1252 character in argparse help=/description=/epilog= (printed to stdout on --help) or a pytest skip/xfail reason (printed under -rs) was invisible. PR 1403 had to fix one such site by hand. Only the printed arguments are walked. A default=, choices= or a skipif condition is compared or evaluated, never printed, and does not fire. Measured over every reach root: zero hits, so this is a ratchet at zero and changes no source file. Thirteen planted shapes must fire and seven never-printed shapes must not.
…1799) Each module is off the ignore_errors list and clean on linux and win32. Real test defects mypy found: - test_secret_rotation: the fake sink lacked the enforced= keyword the runner passes on the enforced path, so that path would raise TypeError. - test_session_rotation_primitive: seeded a 2-tuple into a map whose entries are (count, first_seen, user_id). - test_transform_concurrency: a wrapper annotated -> None returned the handoff's bool. - test_uploads_cross_process_quota: key annotated bytes, passed a str. - test_security_cli: patched json.loads through cli.json, an unexported name; it now patches the same module object directly.
…KLOG #1799) Each module is off the ignore_errors list and clean on linux and win32. Two Windows-only tests gain a platform skip mypy can read; the existing skipif marks already skip them elsewhere. Fakes now subclass the connector ABCs they stand in for, and unused or mis-coded ignores are gone.
…KLOG #1799) Each module is off the ignore_errors list and clean on linux and win32. Handlers registered on a Registry now take the Payload the registry declares and narrow to Message, which the runner hands them by default. Real test defect: test_pooled_rider's three fakes and test_pooled_runner's collector overrode DestinationConnector.send without its metadata keyword.
Argparse arm: walk every argument of an argparse call. argparse prints metavar=, version=, choices=, option strings, subcommand names and positional group titles, which the keyword allow-list missed. A `__doc__` in a console-bound argument now resolves to the module docstring, because `description=__doc__` is how this tree spells it. Pytest arm dropped. Pytest's TerminalWriter.write_raw catches UnicodeEncodeError and writes the text unicode-escaped, so a reason never aborts. A test re-derives that premise. The PR 1403 comment that said it aborted carries a dated correction. tee/ may not import the engine, so under the reach gate it accepts the direct sys.stdout.reconfigure form. A test re-derives that tee imports nothing from messagefoundry. The walk now lists tracked plus untracked-not-ignored files, so a Builder's unstaged new file is scanned. An unstaged glyph file under fuzz/ turned the gate red. git failure or an empty listing fails with git's stderr. The census derives gated roots from row paths, not labels. Verdict kinds are a typed Literal. Stale comments fixed.
…KLOG #1799) Each module is off the ignore_errors list and clean on linux and win32. Also strips 188 type: ignore comments that mypy reports unused on both platforms from modules still on the list, each where that was the line's only error; comment-only, so no test behaviour changes.
Covers BACKLOG #1866, cited in the body because the claim gate holds the subject to a claim this worktree does not hold (as PR 1407 did). The connscale red was the stranding budget, not the exact shortfall. 15 of 18 unconfirmed is over max(12, 13), so the excusal clamps to 0. The audit on run 35638437724 read missing_accepted=0. Remainder (1) looks answered by BACKLOG #1292 (PRs 1532, 1537): 0 of 341 merge_group runs since 2026-09-25T19:17Z red this test. Reconcile unchanged. Loss arms (not committed): K=0 green, K=1 and K=3 red. PR title: test(harness): the connscale #1866 red was the stranding budget Banner: PARTIAL -- remainder (1) answered by #1292, pinned here; arm 2 shown. Intake floor stays an owner question.
…KLOG #1799) Each module is off the ignore_errors list and clean on linux and win32. Also, in modules still listed: ConnectorType now comes from config.models (wiring does not export it), and fake responses' __exit__ returns None. test_anon_parity now hands the vendored tee copy its own DEFAULT_RULES rather than the engine's, which is what a parity check should compare.
…KLOG #1842) RE-DERIVE left the step log. A success run over an uncensored row now raises a ::warning annotation, graded RE-DERIVE or RE-SIZE, with no change to the exit code. The self-check gained two record arms. Third re-derivation, 2026-09-29: rows 3:44 / 5:05 / 5:43 over merge_group and pull_request runs to 2026-09-29T20:38Z. Caps move to 6 / 7 / 8 by ceil_minute(1.35x). Proposed PR title: CI step margin: escalate a rotting record, and re-derive the web console rows a third time (BACKLOG #1842) Proposed banner: BUILT 2026-09-29 -- option 2 shipped: RE-DERIVE / RE-SIZE now raise a warning annotation and never red a leg; the web console rows re-derived to 3:44 / 5:05 / 5:43 and caps to 6 / 7 / 8. Open: the lead time is set by the sizing rule, a few percent.
The tee/ second remedy is withdrawn. It accepted a stdout reconfigure anywhere in a file, the position-free check the chokepoint rule exists to refuse. tee/ stays gated with no remedy but ASCII until it vendors the chokepoint. That is recorded as open. Pytest reasons are an arm again. They are corrupted rather than aborted, the same failure the gate already refuses on stderr. The argparse arm skips default=, type=, nargs= and similar, which argparse does not print, and walks dest=. main.__doc__ resolves, and a bare __doc__ inside a class body no longer resolves to the module's. The planted control now passes repo-relative paths and requires the planted line among the hits. The census reads tracked files only and names a repo-root .py plainly. scripts/ pins a top-level file. A git binary missing from PATH fails with a message. Proposed PR title: cp1252 gate covers every root holding Python, walks git's file list, and sees argparse and pytest text (BACKLOG #1030) Proposed banner: PARTIAL. The reach gate now walks every top-level directory holding Python (a census test fails on a new one), through one git-listed walk. The engine wrappers are folded into the parametrization, and argparse, pytest-reason and __doc__ text is gated. Remaining: the DECODE direction, unbuilt (2026-09-29: 371 subprocess calls pass text=True with no encoding, 348 under tests/; ruff PLW1514, preview-only, finds 4 file reads with no encoding); a remedy for tee/ (vendor the chokepoint); and tee/__main__.py printing runtime values unhardened.
…LOG #1799) Each module is off the ignore_errors list and clean on linux and win32. Also None-checks one-line reads of an Optional row across modules still listed. Real test defects: test_tls_policy's yield fixture was annotated as returning a tuple; test_alert_failover's fake store lacked a method the sink's protocol requires; test_asvs_phase0 now builds a real WebSocket over a hand-made scope instead of a namespace duck.
#1799) Each module is off the ignore_errors list and clean on linux and win32. A cursor row and a message dict no longer share one local name in the None-checked reads. Real test defect: test_retry_cap_default annotated the inbound connection its graph helper returns as object.
#1799) Each module is off the ignore_errors list and clean on linux and win32. test_store_once_deliver_many became clean from the None-checked reads alone, the dead-entry case the new CI check exists to catch. Also None-checks more Optional row reads in modules still listed.
…#1799) Each module is off the ignore_errors list and clean on linux and win32. The store, retention, staging and encryption suites now None-check their Optional reads, and their fake coordinator and alert sink subclass the real null implementations instead of standing in as partial ducks.
…#1799) Each module is off the ignore_errors list and clean on linux and win32. The ADR 0075 suites swap store.sqlserver's uuid4 through one harness helper instead of assigning an unexported module name under ignores. Real test defect: test_alert_state's fake store lacked a method the sink's store protocol requires.
…#1799) Each module is off the ignore_errors list and clean on linux and win32. Fakes subclass the real connector and sink bases, helpers declare the real return types, and raw SQL reads narrow the engine store to the SQLite store they rely on. test_adr0075_batch_error_attribution imports its harness package-qualified, so mypy sees it rather than Any.
…#1799) Each module is off the ignore_errors list and clean on linux and win32. Real test defect: test_mllp_tls started three MLLP sources with a plain lambda as the inbound handler. MLLPSource awaits its handler, so the first message any of them received would have raised TypeError; the tests only probed the handshake, so none ever did. They now share an async _ack_aa. test_log_write_guard's legacy-key refusals go through model_validate, which is the typed way to hand pydantic unknown keys.
…#1799) Each module is off the ignore_errors list and clean on linux and win32. Real test defects: test_cert_expiry's fake sink lacked the enforced= keyword the secret-rotation runner passes; test_fifo_index_migration's helper was annotated list[str] but returns positions. Inputs outside a declared Literal set, kept on purpose because the refusal is the subject, carry a targeted ignore that says so.
… (BACKLOG #1799) test_crl_held_copies borrows test_cert_expiry's _RecordingSink, which is now a LoggingAlertSink, so its arg-type ignore became unused and the tests mypy pass would have failed on it. Caught by a whole-directory run.
…#1799) Each module is off the ignore_errors list and clean on linux and win32, checked by a whole-directory run on both platforms. Module-global patches (sys.platform, subprocess.run) now name the module they patch directly; they were always patching that same global object.
# Conflicts: # CHANGELOG.md
…1799) The dead-entry check flips only an ignore_errors line inside a mypy override, so coverage.py's key of the same spelling cannot redden it; a planted control pins that. Every ADR 0075 suite imports its harness package-qualified. test_adr0157_demote_teardown keeps mypy's comparison-overlap signal with a note: that guard never drives _teardown_unsafe. Proposed PR title: CI fails on a clean tests-ratchet entry; 149 test modules type-fixed off it (BACKLOG #1799) Proposed banner: PARTIAL -- a CI step now fails on a listed module that is already clean; the ignore_errors list is down from 177 to 28 modules (568 errors on linux, 569 on win32 with the exemption off).
One conflict, tests/test_security_cli.py: main patched json.loads through cli_common.json after the CLI extraction; this branch patches the json module directly, which is the same object and type-checks. Kept this branch's side. Whole-directory mypy over tests is clean on linux and win32 after the merge, and the dead-entry check passes. Proposed PR title: CI fails on a clean tests-ratchet entry; 149 test modules type-fixed off it (BACKLOG #1799) Proposed banner: PARTIAL -- a CI step now fails on a listed module that is already clean; the ignore_errors list is down from 177 to 28 modules (568 errors on linux, 569 on win32 with the exemption off).
|
QA: main merged in after PR 1828 landed. New head Resolved as the Lander directed:
Also resolved:
Checks:
Review: code-review at xhigh, two rounds. It found no correctness bug in the resolution. The prose findings are fixed, except one: main's own "6:10 or longer" in the third re-derivation note. The true red line is 6:09.2, and that sentence is main's to fix. Before flipping the #1842 ledger row: this PR's body and its proposed #1842 banner still say this PR re-derived the web console caps to 6 / 7 / 8 (rows 3:44 / 5:05 / 5:43). After this merge it re-derives nothing. The caps and rows are main's PR 1859 values: 6 / 8 / 8 over 4:15 / 5:40 / 5:43. What this PR adds for #1842 is the |
|
CI failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/36819562275 |
|
CI failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/36822096585 |
|
CI failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/36826480887 |
|
Security failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/36832387843 |
No textual conflict. Semantic: PR 1843 added two functools.partial calls in tests/test_docs_security_pathways.py that pass a SimpleNamespace stand-in as AuthService's self. This branch's stricter tests mypy profile covers that file, so "Type-check (mypy, tests)" failed in six merge-group runs. Both calls now carry the per-argument `# type: ignore[arg-type]` the file already uses for the same stand-in on the same AuthService methods (the partial and calls in the sibling helpers above). mypy over the whole tests tree is clean on win32 and linux, and the ratchet check finds no dead entries.
…view) Two comments said auth_provider is the one field _mfa_required_for reads off a user. It reads none (BACKLOG #1144). Comment only.
|
QA: main merged at Fixed the cause of the six red merge-group runs. "Type-check (mypy, tests)" failed at
Comment fix (branch side). Two comments said Checks:
Review: code-review at xhigh, one round. No correctness bug in the merge's lines. Its notes on this branch's other content, left as they are:
|
|
CI failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/36835249856 |
|
CI failed in Its own head can still be green: the queue revalidates the merge, and the path gates that skip on a pull request run there. Read the run before retrying. https://github.com/MEFORORG/MessageFoundry/actions/runs/36840329310 |
Batch 181 (ci-workflows), wave PR A. Five items, one merge commit each, built on origin/main
0f5ae18a8a. Batch head51abf88624.Landing order: this PR lands BEFORE batch 181 PR B. Branch
b181-2093conflicts withb181-1799(in this PR) intests/test_log_write_guard.py, so #2093 is held back and gets re-merged onto main once this PR lands.Checks the Manager ran on the combined tree
ruff check .passed.ruff format --check .reported 1583 files already formatted.mypy messagefoundry messagefoundry_webconsole --exclude messagefoundry/tray/: no issues, 322 files.mypy --explicit-package-bases tests --platform linux: no issues, 1025 files.python scripts/ci/mypy_ratchet_check.py: all 28 listed modules still report errors on linux and win32.python scripts/hooks/ledger_check.py --ci: exit 0.pytest -n 6over all 163 changed test files: 4955 passed, 414 skipped (Postgres and SQL Server environment skips).BACKLOG #1971: the AD local-account conflict test can fail again
b181-1971@3910a8b59f980602e6e1df13fab447aa4b597082_dispatch_loginrefuses up front, so the conflict branch was never reached. It now drivesPOST /auth/negotiate(Windows SSO) into_complete_ad_login. It asserts:auth.login_failedrow with reasonlocal_account_conflict;['directory_identity_conflict'] == ['local_account_conflict']. The old test passed under the same mutation.tests/test_auth_hardening.py29 passed, code-review at xhigh (one round).auth/service.py(about line 3927) sets noreasonon itsLoginOutcome, while the OIDC leg does;_no_sleepremain acrosstests/;SHIPPED -- the M4 conflict test drives Windows SSO into _complete_ad_login and pins the local_account_conflict audit row; red with the branch removed.BACKLOG #1842 (option 2): RE-DERIVE escalates, and the web console rows re-derived a third time
b181-1842@1b0e05ad408e0d4795987263977e0d8b77981ba8::warningannotation, and a summary banner, in two grades:SIZING_MULTIPLE,SIZING_FLOOR_MINUTESandsized_cap_minutes()now live only instep_margin.py.self_checkgained RE-DERIVE and RE-SIZE arms, each paired with a run under the record, and each pair must exit alike.merge_group/pull_requestruns, 2026-09-26T02:16Z to 2026-09-29T20:38Z.mypy --strict scripts/ci/step_margin.py,tests/test_ci_step_margin.py53 passed, 387 across ci tests, code-review at xhigh (two rounds).Tests (pytest)row is stale at 16:08, so engine runs will now draw RE-DERIVE, which is correct.BUILT 2026-09-29 -- option 2 shipped: RE-DERIVE / RE-SIZE now raise a warning annotation and never red a leg; the web console rows re-derived to 3:44 / 5:05 / 5:43 and caps to 6 / 7 / 8. Open: the lead time is set by the sizing rule, a few percent.BACKLOG #1866 (remainder 1): the connscale red was the stranding budget, pinned
b181-1866@26736badf51a3119b71087ac3c7bb7d49b15eb52(main merged in to clear an additive CHANGELOG conflict; the item commit is963f6ed3c1)missing_accepted=0.merge_groupruns since have failed the test.test_connscale_reconcile_the_2026_09_21_reds_were_the_stranding_budget;test (windows-2025, py3.14),repo harness tests (windows-2025).PARTIAL -- remainder (1) answered by #1292, pinned here; arm 2 shown. Intake floor stays an owner question.BACKLOG #1030 (remainder): the cp1252 gate covers every root holding Python
b181-1030@624cf81d719d2d61e8dc69eedce064841eb6dc89_files_under, now serves every surface. The engine wrappers are folded into the parametrization.__doc__text is gated: 18 planted shapes fire and 7 never-printed shapes do not.tests/test_cp1252_console_safety.py84 passed, code-review at xhigh (two rounds).subprocesscalls passtext=Truewith no encoding;tee/__main__.pyprints runtime values unhardened (review-reported).PARTIAL -- the reach gate walks every top-level directory holding Python with a census test; one git-listed walk; engine wrappers folded; argparse/pytest-reason/__doc__ text gated. Remains: the decode direction (371 subprocess text=True sites with no encoding, measured 2026-09-29), a tee/ remedy (vendor the chokepoint), and tee/__main__.py runtime prints.BACKLOG #1799 (remainder): the tests mypy ratchet goes from 177 to 28, and a clean entry now fails CI
b181-1799@d19182cbaec61638edd98acaf8a317326666c83cscripts/ci/mypy_ratchet_check.pyruns as a new ci.yml step. It fails on any listed module that is already clean on linux and win32, and it refuses to pass on a flip that did not take.test_mllp_tlsstarted sources with a synclambdahandler;enforced=;list_active_alert_instances;test_adr0157_demote_teardown::test_a_shutdown_teardown_calls_no_demotion_helpernever drives_teardown_unsafe, so its named mutation would not fail it. A targeted ignore with a note keeps mypy's signal visible.ConnScaleRecordack_p*_ms=Noneagainst a float type intest_connscale_empty_claims_per_msg.PARTIAL -- a CI step now fails on a listed module that is already clean; the ignore_errors list is down from 177 to 28 modules (568 errors on linux, 569 on win32 with the exemption off).Claims held by the Builders' worktrees (release after merge)
#1971, #1842, #1866, #1030, #1799.