Skip to content

chore(release): promote develop → main - #360

Open
ywatanabe1989 wants to merge 15 commits into
mainfrom
develop
Open

chore(release): promote develop → main#360
ywatanabe1989 wants to merge 15 commits into
mainfrom
develop

Conversation

@ywatanabe1989

Copy link
Copy Markdown
Collaborator

What this is

A develop → main promotion PR, opened by scitex-dev as part of a fleet-wide sweep. Your default branch is behind your own develop, which means main no longer reflects what has been released.

You decide whether to merge it. I do not merge other packages' default branches — opening a PR is reversible and CI-gated; merging is neither. If this is wrong for your repo, close it and nothing is lost.

Why it was opened

Measured across the fleet: 22 repos had main behind their newest tag. That gap is not cosmetic — it means:

  1. Anyone reading your default branch sees stale code.
  2. A published release on PyPI can have no corresponding commit on main.
  3. The next promotion accumulates, so the diff only gets harder to review.

On the "behind" count

If the compare view says main is also behind develop by a few commits, that is expected and not divergence: merge-based promotion makes main accumulate merge commits that develop never sees. It is the normal steady state for this workflow.

Authorisation

Operator ruling, 2026-08-04: PRs against repos scitex-dev does not own are explicitly authorized. This sweep was held for six days waiting on exactly that word, and it applies here.

Tracked on card default-branch-behind-published-release-promotion-gap-20260729.

ywatanabe1989 and others added 15 commits June 22, 2026 12:19
Replace the GitHub-hosted release workflow with the proven self-hosted
SIF pipeline (test->build->publish->release inside the reused scitex-ci
ci-cpu.sif via apptainer exec), matching the fleet canary
(openalex-local). The bare Spartan compute node has no Python, so
actions/setup-python and the Docker-based pypa/gh-action-pypi-publish
cannot run there; publish now does MANUAL OIDC trusted publishing inside
the SIF (GitHub OIDC JWT -> PyPI mint-token -> twine upload). Trust
config on PyPI is unchanged.

- KEEP trust-bound filename pypi-publish-and-github-release-on-tag.yml
  (PyPI trusted publisher is bound to the workflow filename).
- Add the 4 .github/ci/{exec,run,build,publish}-in-sif.sh helpers.
- Strip the auto sync-main job (develop->main is a deliberate PR).
- runs-on from Actions Variable CI_RUNS_ON; SIF + apptainer paths from
  SCITEX_CI_SIF / SCITEX_CI_APPTAINER (same as pytest-matrix).
- --cov=src/scitex; environment url https://pypi.org/p/scitex;
  unique-per-run TMPDIR; matplotlib Agg + warm font cache guarded.
- fail-loud: a missing SIF/shim/interpreter is a HARD error.
…d (pinned-in-core) (#340)

Complete the mid-release 2.30.2 reconcile to TRUE current-latest PyPI
versions, pinned in CORE [project.dependencies] (not extras-only) so
`pip install scitex` and `uv pip install scitex[all]` resolve the same
stable set.

Leaf bumps (current -> latest):
- figrecipe       0.28.20 -> 0.29.5
- scitex-audio    0.2.13  -> 0.3.0
- scitex-cv       0.1.5   -> 0.2.0
- scitex-dev      0.18.1  -> 0.20.1
- scitex-io       0.3.2   -> 0.3.3
- scitex-writer   2.17.5  -> 2.22.0

- Add scitex-pd==0.1.6 to core deps AND the [pd] extra (which flows into
  [all]) so `scitex.pd` works out of the box.
- Bump umbrella version 2.30.2 -> 2.30.3 (2.30.2 already published).

Conflict-verified: `uv pip compile` of the full resulting pin set exits 0
(732-line lock, no conflicts).
)

The self-hosted SIF release pipeline (run-in-sif.sh) drifted out of parity with
the hardened ubuntu workflow, breaking the v2.30.3 release at the 3.13 test gate:

- It installed only `.[all,dev]`, but the umbrella-aliased PEER standalones
  (scitex-gen, scitex-dsp, ...) are NOT in [all]. So scitex_gen was never
  refreshed and the test used the SIF's baked, stale copy (missing `to_even`),
  failing tests/integration/test_cross_package_imports.py. Reinstall the peers
  FRESH into the same --target so they shadow the baked copies on PYTHONPATH.
- It ran bare `pytest tests/` with no quarantine. Restore the ignores the
  hardened workflow uses: tests/e2e + the cross-package gate (segfault-prone),
  and tests/examples/test_09_dev.py (hard-requires scitex_hub, which is
  umbrella_skip by design and never in the [all] SIF).
figrecipe 0.29.5->0.29.9, scitex-writer 2.22.0->2.23.0, scitex-clew 0.2.17->0.2.18
(PS-170 freshness; strict pin audit green). figrecipe 0.29.9 lets downstream
research projects pin figrecipe==0.29.9 consistently alongside scitex==2.30.4.
…eterministic (#343)

The v2.30.4 release SIF flaked on test_bundle_submodule_is_a_package:
`import scitex.io as sio; sio.bundle` asserts attribute access WITHOUT
importing the submodule, so it only passes when a sibling test imported
scitex.io.bundle first — nondeterministic under pytest-xdist worker
distribution (reproduces back to 2.30.0; not a regression, not the pin bump).
Product is fine: `import scitex.io.bundle` is the supported path and works.
Import it explicitly so the assertions are deterministic on every worker.
scitex-writer 2.23.0->2.24.1 (post-compile fail-loud gate, incident fix),
scitex-dev 0.20.1->0.21.0 (compliance-linter trio), scitex-clew 0.2.18->0.2.22.
Strict pin audit green.
…for SIF rebuild (#346)

* chore(umbrella): scitex 2.30.6 — re-pin members to current-published for SIF rebuild

* chore(umbrella): narrow 2.30.6 to minimal set (clew 0.16.0 / notification 0.2.9 / notebook 0.1.2)

Revert the broad fleet-latest bumps (writer/session/dev/container/dataset/
scholar/ssh) that broke the umbrella thin-wrapper MCP-parity test
(test_umbrella_exposes_writer_mcp_tools) and segfaulted pytest-matrix.
The SIF rebuild only needs the minimal alignment set; broad 'fleet on
latest' re-pins require per-member thin-wrapper regen and land as a
follow-up.
…gregator (#347)

* rescue: pre-stop autosave scitex-python@20260703T223658Z

* fix(mcp): bounded per-peer mount so one hung peer can't darken the aggregator

The umbrella `scitex serve` aggregator fronts ~33 packages' MCP tools by
importing each peer's `_mcp_server` and mounting its FastMCP at module-load
time. Previously each peer was resolved SEQUENTIALLY and SYNCHRONOUSLY. If a
single peer's import hangs at init (real case: scitex-todo store-wedge stalls
20s+), the whole `scitex._mcp` import never completes and EVERY peer's tools
go dark — the failure concentrates 33x vs the per-server split.

Fix: resolve each peer's FastMCP concurrently in a bounded DAEMON thread
(`_resolve_peers_bounded`). Threads start at once and are joined against one
shared deadline, so total load time is ~max(peer) bounded by the per-peer
budget — never the sum, and a hung thread can't block interpreter exit. On
timeout / exception the peer is SKIPPED with a warning ("... unavailable this
session") and the healthy peers still mount. Budget is configurable via
`SCITEX_MCP_PEER_TIMEOUT` (default 8s).

Mounting stays on the MAIN thread: only the peer IMPORT is slow/hang-prone;
`safe_mount` is fast and mutates shared parent-server state, so it is kept
single-threaded to avoid concurrent-mutation races.

Preserves all prior behavior: `_is_enabled` env gate, `_NAMESPACE_ALIASES`,
`_SKIP_CATEGORIES`, `register_peer_extras`, `register_umbrella_tools`, the
mounted-count log, and `SCITEX_MCP_USE_<NS>=0` gating. `register_all_tools`
gains injectable `iter_registry` / `peer_timeout` params (defaults unchanged)
so tests drive the real path without patching module globals.

Tests (tests/scitex/test_mcp_bounded_mount.py): real fixture peers written to
disk — a 30s-sleep hung peer, an ImportError peer, a sys.exit peer, fast
peers. Assert the bounded resolve returns within the budget, the hung peer is
skipped + warned, the fast peers still mount, and the env gate holds.

* fix(mcp): serialize bounded peer resolve — concurrent imports deadlocked CI collection

PR #347's pytest-matrix hung for 1h30m (job timeout, all 3 py versions) with
"test session starts" printed and then nothing — i.e. a hang during COLLECTION,
before any test ran, where pytest-timeout's per-test SIGALRM cannot fire.

Root cause: the first cut resolved every peer's `_mcp_server` import CONCURRENTLY
(one daemon thread per peer, ~33 fired at once). Importing a large, interdependent
package set from many threads simultaneously races the CPython import machinery and
can deadlock via cross-thread circular imports that never occur when modules are
imported one at a time. That deadlock strikes at `from scitex import _mcp` import
(register_all_tools runs at module load) — which every test module triggers at
collection. `develop` passes because its resolve is sequential; the concurrency
was the regression.

Fix: resolve peers SERIALLY. Each peer still imports in its own bounded daemon
thread (`_resolve_one_peer_bounded`, joined for at most `SCITEX_MCP_PEER_TIMEOUT`,
default 8s) so a hung/wedged import is abandoned + skipped and can never block
interpreter exit — but only ONE import is ever in flight, so imports stay as safe
as develop's sequential loop while gaining the per-peer hang bound. Wall cost is
the sum of the healthy peers' (fast) import times plus the timeout per wedged peer
— a one-time startup cost paid for reliability (the original "~max(peer)"
concurrency goal is knowingly traded away; correctness first).

Verified locally: real `from scitex import _mcp` completes in ~8s and leaves NO
lingering non-daemon threads (so the main-thread timeout signal can always fire);
`test_mcp_entrypoint.py` matches the develop baseline (no new failures, no hang).

Tests: added `_INFINITE_PEER` (import blocks on `threading.Event().wait()`, never
set — the real store-wedge shape, not a bounded sleep) with a fixture asserting the
bounded resolve returns within the budget, skips the wedged peer, and still mounts
the co-resident fast peer. All hang fixtures are written to tmp dirs and imported
ONLY inside the bounded code path at test time — never at module/collection time,
so pytest can never auto-collect or import them into a collection hang.
25 tests pass.
…ned MCP aggregator (#348)

Bundles the merged #347 bounded-per-peer mount hardening (aggregator no
longer darkened by one hung peer) with the clew 0.17.0 upgrade
(supersedes the 2.30.6 clew-0.16.0 stopgap). This is the version sac
floors (scitex>=2.30.7) for the .mcp.json single-aggregator swap.
… guard (#349)

* fix(mcp): skip orochi orchestrator in umbrella aggregator cold-start

The umbrella MCP aggregator serially resolves each ecosystem peer's
_mcp_server at import time. scitex-orochi is the single-instance
agent-communication ORCHESTRATOR — its mcp_server guards sys.exit when a
Telegram bot token / telegram agent-role is present, and it is not a
per-agent tool provider. Auto-mounting it is both semantically wrong and
a cold-start hazard (its heavy import blocks the serial resolution loop).

_iter_registry now delegates the skip decision to a new _mount_skip()
helper which prefers scitex-dev's is_mcp_mountable() SSoT and falls back
to the local archived/category/mcp_mountable-field checks plus a
_LOCAL_UNMOUNTABLE guard (scitex-orochi) so the orchestrator is skipped
even against an older scitex-dev that predates the SSoT helper.

Coordinated two-repo change with scitex-dev
_ecosystem._core.is_mcp_mountable / _MCP_UNMOUNTABLE.

Adds 4 focused tests to test_mcp_entrypoint.py.

* fix(mcp): also skip scitex-types (zero tools, heavy import) in aggregator

scitex-types ships no _mcp_server (zero MCP tools) but importing it pulls
the heavy scientific stack (numpy/torch/…). Probing it for a non-existent
FastMCP is pure cold-start waste. Add it to _LOCAL_UNMOUNTABLE (kept in
sync with scitex-dev _core._MCP_UNMOUNTABLE).

This rides on top of the #347/#348 bounded per-peer mount: skipped peers
are removed from the peer list before resolution, so no bounded daemon
thread is even spawned for them.

Adds 2 tests (types excluded from _iter_registry / _mount_skip True).
The umbrella aggregator's _mount_skip prefers scitex-dev's is_mcp_mountable
SSoT and falls back to the local _LOCAL_UNMOUNTABLE set when an older
scitex-dev (without that helper) is installed. scitex-str ships no _mcp
server (zero tools) yet importing scitex_str eagerly pulls pandas + numpy
via its _search / _plot submodules — pure cold-start waste, exactly like
scitex-types. Add it to the fallback set so the skip holds across the
coordinated two-repo rollout even before the scitex-dev SSoT bump is
installed.

Diagnosed in sac's real-SIF re-verify of umbrella 2.30.8. Pairs with
scitex-dev _MCP_UNMOUNTABLE bump and scitex-resource lazy-import PR.

Tests: assert _LOCAL_UNMOUNTABLE covers orochi/types/str and that
_mount_skip returns True for scitex-str via the forced fallback path.
…letion group, categorized help (#352)

* fix(cli): repair writer mount crash and mount scholar

- scitex writer --help crashed with AttributeError: the registry probe
  picked up scitex_writer._cli.main (a plain console-script function)
  instead of the click group. Add the doctrine 5b re-export shim
  (scitex/cli/writer.py -> scitex_writer._cli.main_group) and make the
  lazy loader skip non-click-command attributes so a probe can never
  mount an uncallable object again.
- scitex scholar was not mounted: no probe matched the standalone's
  entry point scitex_scholar._cli_main:cli. Add that probe shape.

* refactor(cli): retire duplicate umbrella namespaces via warn-phase aliases

notify->notification, verify->clew, events->event, socialia->social.
The old names are no longer registered as lazy subcommands; when
scitex-dev's click_compat helper is importable (scitex-dev > 0.21.0)
they come back as hidden warn-phase deprecated aliases that forward to
the canonical command (doctrine 3-phase ladder, removed in v3.0); with
an older scitex-dev they are simply excluded.

figrecipe/plt is intentionally NOT deduplicated: scitex-plt is a
published identity-alias package for figrecipe and doctrine 5b's brand
table documents 'scitex plt' as a figrecipe mount.

Hidden commands (the aliases) are now skipped in root help output.

* refactor(cli): make completion the canonical noun group

Doctrine 1b (04_exceptions.md, amended 2026-07-07): a bare completion
command is banned; the completion GROUP with verb subcommands is the
canon. Changes:

- move the group out of main.py into scitex/cli/completion.py (lazily
  mounted like every other wrapper; main.py shrinks well under the
  512-line cap)
- bare 'scitex completion' now shows group help instead of silently
  auto-installing
- 'completion install' gains --dry-run: prints the target rc file and
  the completion script without touching the filesystem (subsumes the
  old bash/zsh/fish script-dump leaves)
- 'completion bash|zsh|fish' become hidden warn-phase deprecated
  leaves: still print the script, warn on stderr, removed in v3.0
- root help examples updated ('scitex completion --show' never existed)

* feat(cli): categorized root help, -V flag, real peer one-liners

- root help now renders the doctrine 4a fixed ordered category headers
  (Core / Data & Sync / Service / Diagnostics / Introspection / Shell;
  Other is the catch-all and stays empty) — implemented inside
  LazyGroup.format_commands so no lazy subcommand is imported for help
  (scitex-dev's CategorizedGroup resolves real command objects, which
  would defeat the lazy mount and reintroduce the ~45s cold start)
- add -V as the short form of --version (doctrine 08 universal flags)
- ~25 mounted groups whose one-liner degraded to the bare package name
  when the peer was not installed (dataset, git, hpc, newb, datetime,
  ...) now fall back to a curated one-liner sourced from each package's
  own pyproject description (_INTERNAL_HELP renamed _FALLBACK_HELP)

* test(cli): cover slice-5 umbrella CLI standardization

- writer/scholar mount smoke (--help exits 0)
- retired duplicates hidden from help; warn-phase alias help page when
  scitex-dev click_compat is importable, unknown-command otherwise
- completion noun group: verbs listed, deprecated bash/zsh/fish leaves
  hidden but still printing the script with a stderr warning,
  install --dry-run prints plan and never writes
- -V short flag; 4a category headers, order, and empty Other
- builder unit tests: alias exclusion, scholar probe shape, writer
  wrapper override, fallback one-liners
Pilot org-level reusable-workflow migration (operator-approved
2026-07-10 incident remediation), following the pattern merged in
scitex-ai/scitex-stats#69.

Converted (clean mechanical match — job body verified byte-identical
to the reusable workflow before conversion):
- auto-merge-to-develop.yaml -> caller stub for
  scitex-ai/.github/.github/workflows/auto-merge-to-develop.yml@main

Left AS-IS (do not cleanly match the current reusable-workflow catalog
today — converting would silently change behavior or target an
unverified runner; see PR description for detail on each):
- pytest-matrix-on-ubuntu-py3-11-3-12-3-13.yml: runs on ubuntu-latest
  (not self-hosted spartan-cpu) with CPU-torch pre-pin, peer-standalone
  installs, a PS-170 umbrella-pin audit step, and a segfault-retry +
  JUnit-report pass/fail decoupling scheme with none of that present in
  the reusable pytest-matrix.yml.
- import-smoke-on-ubuntu-py3-12.yml: runs on ubuntu-latest with plain
  pip/venv and a hardcoded package name, vs. the reusable workflow's
  self-hosted/uv/derived-package-name approach.
- scitex-quality-audit-on-ubuntu-latest.yml: audits the WHOLE
  ecosystem (clones every scitex-* repo) rather than auditing only the
  calling repo, which is what the reusable quality-audit.yml does —
  not the same job semantically.
- rtd-sphinx-build-on-ubuntu-latest.yml: also commits the built HTML
  bundle back into src/scitex/_sphinx_html/ on develop pushes, a
  repo-specific step with no equivalent in the reusable workflow.
- cla.yml: no `push` trigger / no owner-bypass job (structurally
  simpler than the reusable cla.yml), and uses a differently-named
  secret (CLA_PERSONAL_ACCESS_TOKEN vs. the reusable workflow's
  hardcoded GH_PERSONAL_ACCESS_TOKEN) — converting risked silently
  breaking the CLA-signature push.
- newb.yml / newb-docs-quality-on-ubuntu-latest.yml: no reusable
  workflow exists for this job yet (two near-duplicate files already).
- pypi-publish-and-github-release-on-tag.yml: untouched per explicit
  instruction (PyPI OIDC trusted publishing does not support
  workflow_call).

Branch protection: confirmed via `gh api .../branches/{develop,main}/
protection` that neither branch has protection configured (404 on
both) — nothing to update.
chore(ci): migrate to scitex-ai/.github reusable workflows (pilot follow-up)
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.

1 participant