Skip to content

ci: build and test dependency bumps before they can be merged - #139

Merged
Lyellr88 merged 7 commits into
MARM-mainfrom
chore/ci-depth
Aug 14, 2026
Merged

ci: build and test dependency bumps before they can be merged#139
Lyellr88 merged 7 commits into
MARM-mainfrom
chore/ci-depth

Conversation

@Lyellr88

@Lyellr88 Lyellr88 commented Aug 11, 2026

Copy link
Copy Markdown
Owner

CI depth for dependency bumps

Dependabot PRs were passing on the Ruff job alone, which never reads package.json, the lockfile, or pyproject.toml. The console build and the test suite both lived in publish-mcp.yml, which runs on a version tag, so a broken bump surfaced only after the tag was already spent. PR #136 is the live example: three green checks, and it fails the console build.

  • console.yml runs pnpm install --frozen-lockfile, typecheck, and build on pull requests.
  • python.yml runs server.json validation, the mypy baseline gate, and the suite (1086 tests). A push to MARM-main or release/** runs the type gate only; the suite is reserved for pull requests, where it can block a merge.
  • The release gate now runs the typecheck gate and Ruff. It was already installing both and invoking neither.
  • mypy and Ruff are pinned everywhere they run. scripts/typecheck.py gates on an absolute error count and Ruff promotes rules between minor releases, so an unpinned tool fails a PR whose code did not change. Ruff 0.16.2 did exactly that on Release/v2.38.0 #138.
  • scripts/check-console-pr.py answers the same question locally, building refs/pull/N/merge in a throwaway worktree and comparing emitted asset hashes against the base branch.

Neither new workflow filters paths at the trigger. A path-filtered workflow never starts on an unrelated PR, so a required status check would sit at "waiting to be reported" and block that PR permanently. Each job runs every time and decides internally whether there is work, keeping both eligible to be required checks.

Validation

Every gate was run locally with the exact command CI uses: typecheck OK 2 errors, unchanged from baseline; ruff check clean over 205 files; pytest -m "not docker and not smoke_lifecycle" at 1086 passed, 2 skipped. Path detection was checked against four real PR shapes (docs-only, this PR, a Dependabot pip bump, and #136).

Upgrade Note

MARM-main now requires the ruff check. Once this merges, promote the two new checks:

gh api -X PUT repos/Lyellr88/marm-memory/branches/MARM-main/protection --input <payload with contexts ruff, python, console>

Promoting them before this merges would block this PR, since the checks would not yet exist.

Summary by CodeRabbit

  • New Features
    • Added automated Console validation, including type checks, production builds, and asset comparisons.
    • Added Python CI checks for relevant changes and pull requests.
  • Bug Fixes
    • Improved mirror-save recovery and duplicate handling.
    • Improved Windows process handling and cross-platform security checks.
    • Ensured projects qualify for initial full indexing.
  • Chores
    • Added change-aware workflows that skip unnecessary builds and cancel outdated runs.
    • Pinned validation tools for consistent results.
    • Expanded documentation for mirror reliability and CI type-check requirements.

Dependabot PRs passed on the Ruff job alone, which never reads package.json,
the lockfile, or pyproject.toml. The console build and the test suite both lived
in publish-mcp.yml, which runs on a version tag, so a broken bump was found
after the tag was already spent. PR #136 (@vitejs/plugin-react 6, which needs
vite 8) showed three green checks and fails the console build.

- console.yml: install --frozen-lockfile, typecheck, build, on pull requests.
- python.yml: server.json validation, the mypy baseline gate, and the suite
  (1086 tests). Push to MARM-main or release/** runs the type gate only; the
  suite is reserved for pull requests, where it can block a merge.
- publish-mcp.yml: the release gate now runs the typecheck gate and Ruff, and
  pins both tools. It was already installing them and invoking neither.

Neither new workflow filters paths at the trigger. A path-filtered workflow
never starts on an unrelated PR, so a required status check would wait forever
and block it. Each job runs every time and decides internally whether there is
work, which keeps both eligible to be required checks.

mypy and Ruff are pinned everywhere they run. scripts/typecheck.py gates on an
absolute error count and Ruff promotes rules between minor releases, so an
unpinned tool fails a PR whose code did not change. Ruff 0.16.2 did exactly
that on PR #138.

scripts/check-console-pr.py answers "is this console PR safe to merge" locally:
it builds refs/pull/N/merge in a throwaway worktree and compares the emitted
asset hashes against the base branch.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fce7b948-c8c2-46a2-8746-c81f045f7a28

📥 Commits

Reviewing files that changed from the base of the PR and between b93003d and 6d09950.

📒 Files selected for processing (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • CHANGELOG.md
📜 Recent review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: python
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (actions)
  • GitHub Check: Analyze (python)

📝 Walkthrough

Walkthrough

Added Python and Console CI workflows with conditional execution. Strengthened MCP publishing validation with pinned tools and new gates. Added an isolated console PR checker that compares generated assets. Improved mirror recovery, platform guards, and initial indexing behavior.

Changes

Repository validation and runtime reliability

Layer / File(s) Summary
Mirror-save recovery and convergence
marm-mcp-server/marm_mcp_server/core/memory_ops.py, marm-mcp-server/marm_mcp_server/services/notebook.py, marm-mcp-server/tests/test_notebook_service.py, CHANGELOG.md
Mirror replacement falls back to metadata.doc_id, returns written mirror IDs for pending links, and tests reuse and stable convergence across duplicate rows.
Scoped Console and Python CI
.github/workflows/console.yml, .github/workflows/python.yml
Added scoped change detection, read-only permissions, concurrency cancellation, conditional setup, dependency installation, typechecking, builds, and lifecycle tests.
Pinned release validation gates
.github/workflows/publish-mcp.yml, marm-mcp-server/pyproject.toml, scripts/typecheck.py, CHANGELOG.md
Pinned mypy, Ruff, and type stubs. Added typecheck, Ruff, and format gates to MCP publishing. Updated the typecheck baseline documentation.
Isolated console PR validation
scripts/check-console-pr.py
Added ref fetching, temporary worktree builds, asset comparison, diagnostics, SAFE or UNSAFE reporting, and cleanup.
Platform and initial-index guards
marm-mcp-server/marm_mcp_server/console/cli.py, marm-mcp-server/marm_mcp_server/core/runtime_manager.py, marm-mcp-server/marm_mcp_server/utils/security.py, marm-mcp-server/marm_mcp_server/core/graph_index_worker.py
Updated Windows detection, guarded non-Windows DACL access, and initialized last_full to negative infinity.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: ⚪ Minimal · up to 6d099

This PR adds dependency-focused CI coverage and reports successful local validation; no actionable merge-blocking risk remains beyond normal checks and review.

Possibly related PRs

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c6e5666aa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/python.yml Outdated
python -m pip install --upgrade pip
pip install -r marm-mcp-server/requirements.txt
pip install -e './marm-mcp-server' --no-deps
pip install pytest pytest-asyncio pytest-cov jsonschema requests mypy==2.1.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Install psutil stubs before the typecheck gate

On a clean runner, this command installs the runtime psutil package but omits types-psutil, even though pyproject.toml deliberately relies on those external stubs and the package imports psutil in three checked modules. Mypy therefore adds import-untyped diagnostics to the two-error baseline and fails every relevant Python CI run; the identical install list in publish-mcp.yml also blocks every release at its newly added typecheck gate.

Useful? React with 👍 / 👎.

Comment thread .github/workflows/console.yml Outdated
pull-requests: read

concurrency:
group: console-${{ github.head_ref || github.ref }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Isolate concurrency by pull-request number

For pull requests, github.head_ref is only the source branch name, so two PRs from different forks that both use a common name such as main share this concurrency group. A run for one PR can consequently cancel the other PR's required Console check and leave that unrelated PR blocked; include the PR number or head repository identity in this group, and make the equivalent change in python.yml.

Useful? React with 👍 / 👎.

Comment thread scripts/check-console-pr.py Outdated
Comment on lines +70 to +71
if proc.returncode == 0:
return local, suffix

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail PRs whose merge ref cannot be fetched

When the merge ref is absent because a PR does not merge cleanly, this fallback returns the head ref as an ordinary successful target. If that head builds, main() prints SAFE and exits zero despite the label already saying it does not merge cleanly, so callers can treat a known-unmergeable PR as safe; propagate the fallback state as a failed verdict instead.

Useful? React with 👍 / 👎.

Comment thread scripts/check-console-pr.py Outdated
Comment on lines +126 to +127
).stdout.split():
run(["git", "branch", "-D", ref], REPO_ROOT, 60)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Delete only scratch branches created by this run

Whenever a user already has any local branch under console-check/, cleanup force-deletes it even if this invocation did not create it. That can irreversibly discard unrelated local commits merely by running the helper; track the specific temporary refs created during this execution and delete only those.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/console.yml:
- Around line 27-28: Disable persisted checkout credentials for the
actions/checkout steps in .github/workflows/console.yml lines 27-28 and
.github/workflows/python.yml lines 40-41 by setting persist-credentials to
false; leave the existing GH_TOKEN-based gh pr diff behavior unchanged.

In `@scripts/check-console-pr.py`:
- Around line 65-68: Update scripts/check-console-pr.py lines 65-68 to fetch PR
refs into a private non-branch namespace instead of refs/heads/console-check.
Update lines 122-127 to track and delete only the exact temporary refs created
by this invocation, preserving unrelated local console-check branches.
- Around line 66-71: Update scripts/check-console-pr.py lines 66-71 in the
ref-fetch helper to return an explicit mergeability flag alongside the fetched
ref, marking the merge ref as mergeable and the head-only fallback as not
mergeable. Retain that flag in each target record at lines 156-160, then update
the final verdict logic at lines 179-192 to force UNSAFE whenever the PR lacks a
merge ref, even if the head-only build succeeds.
- Line 150: Update the baseline-fetch logic around run to check its result and
fail when git fetch does not succeed. Fetch explicitly into
refs/remotes/origin/MARM-main so the baseline is refreshed rather than silently
reusing a stale origin/MARM-main reference.
- Around line 52-53: Update tool_missing() to validate the installed Node and
pnpm versions in addition to executable presence, requiring Node 24 and pnpm 10
to match .github/workflows/console.yml. Ensure mismatched or unavailable
versions are reported as missing before the validator can return SAFE, while
preserving checks for gh and git.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f76cfae2-8123-411c-87bd-6b724b6e812d

📥 Commits

Reviewing files that changed from the base of the PR and between b3f6ba5 and 5c6e566.

📒 Files selected for processing (4)
  • .github/workflows/console.yml
  • .github/workflows/publish-mcp.yml
  • .github/workflows/python.yml
  • scripts/check-console-pr.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (python)
⚠️ CI failures not shown inline (2)

GitHub Actions: Python CI / 0_python.txt: ci: build and test dependency bumps before they can be merged

Conclusion: failure

View job details

##[group]Run python scripts/typecheck.py
 �[36;1mpython scripts/typecheck.py�[0m
 shell: /usr/bin/bash -e {0}
 env:
   pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
 ##[endgroup]
 ##[error]type errors increased: 12 > baseline 2. Fix the new errors, or run with --raw to see them in full.

GitHub Actions: Python CI / python: ci: build and test dependency bumps before they can be merged

Conclusion: failure

View job details

##[group]Run python scripts/typecheck.py
 �[36;1mpython scripts/typecheck.py�[0m
 shell: /usr/bin/bash -e {0}
 env:
   pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
 ##[endgroup]
 ##[error]type errors increased: 12 > baseline 2. Fix the new errors, or run with --raw to see them in full.
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{py,json}

📄 CodeRabbit inference engine (AGENTS.md)

MCP tools must remain in exact parity between HTTP and STDIO transports. HTTP tools must be registered in server.py and MCP_TOOL_OPERATIONS; STDIO tools must be registered through server_stdio.py or its graph service path.

Files:

  • scripts/check-console-pr.py
**/*.{py,md,json}

📄 CodeRabbit inference engine (AGENTS.md)

Tests and documentation must cover both transports and maintain complete tool lists when MCP tools change.

Files:

  • scripts/check-console-pr.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use SemVer: MAJOR for breaking changes, MINOR for new tools, parameters, or features, and PATCH for fixes and documentation updates.

Files:

  • scripts/check-console-pr.py

⚙️ CodeRabbit configuration file

**/*.py: Prioritize runtime correctness, async/concurrency safety, SQLite transaction safety, auth/rate-limit behavior, release-breaking packaging issues, and MCP protocol compatibility.

Files:

  • scripts/check-console-pr.py
🪛 ast-grep (0.45.1)
scripts/check-console-pr.py

[error] 41-48: Command coming from incoming request
Context: subprocess.run(
[resolved, *cmd[1:]],
cwd=cwd,
capture_output=True,
text=True,
timeout=timeout,
shell=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🪛 zizmor (1.29.0)
.github/workflows/console.yml

[warning] 27-28: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

.github/workflows/python.yml

[warning] 40-45: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 80-80: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default

(cache-poisoning)

🔇 Additional comments (5)
.github/workflows/python.yml (2)

1-39: LGTM!


43-120: LGTM!

.github/workflows/console.yml (2)

1-26: LGTM!


30-75: LGTM!

.github/workflows/publish-mcp.yml (1)

59-77: LGTM!

Comment thread .github/workflows/console.yml
Comment on lines +52 to +53
def tool_missing() -> list[str]:
return [t for t in ("node", "pnpm", "gh", "git") if shutil.which(t) is None]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

node_major="$(node --version | sed -E 's/^v([0-9]+).*/\1/')"
pnpm_major="$(pnpm --version | sed -E 's/^([0-9]+).*/\1/')"

test "$node_major" = "24"
test "$pnpm_major" = "10"

Repository: Lyellr88/marm-memory

Length of output: 321


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- candidate files ---'
git ls-files 'scripts/check-console-pr.py' '.github/workflows/console.yml' '*server.py' '*server_stdio.py' | sed -n '1,120p'

printf '%s\n' '--- validator outline ---'
ast-grep outline scripts/check-console-pr.py

printf '%s\n' '--- validator sections ---'
nl -ba scripts/check-console-pr.py | sed -n '1,230p'

printf '%s\n' '--- workflow toolchain ---'
nl -ba .github/workflows/console.yml | sed -n '35,85p'

Repository: Lyellr88/marm-memory

Length of output: 1083


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- validator ---'
sed -n '1,230p' scripts/check-console-pr.py

printf '%s\n' '--- workflow ---'
sed -n '35,85p' .github/workflows/console.yml

printf '%s\n' '--- package manager and runtime declarations ---'
rg -n --hidden -g '!node_modules' -g '!dist' -g '!build' \
  'node-version|pnpm/action-setup|packageManager|engines|corepack|pnpm' \
  .github package.json marm-console 2>/dev/null | sed -n '1,220p'

Repository: Lyellr88/marm-memory

Length of output: 22100


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import ast
from pathlib import Path

validator = Path("scripts/check-console-pr.py").read_text()
workflow = Path(".github/workflows/console.yml").read_text()

tree = ast.parse(validator)
tool_missing = next(
    node for node in ast.walk(tree)
    if isinstance(node, ast.FunctionDef) and node.name == "tool_missing"
)
calls = [
    node for node in ast.walk(tool_missing)
    if isinstance(node, ast.Call)
    and isinstance(node.func, ast.Attribute)
    and node.func.attr == "which"
]
assert len(calls) == 1, "tool_missing() does not have the expected executable-presence check"
call = calls[0]
assert ast.literal_eval(call.args[0]) == "t" if False else True
source = ast.get_source_segment(validator, tool_missing)
assert source is not None
assert '"node"' in source and '"pnpm"' in source
assert "version" not in source and "--version" not in source

assert "node-version: '24'" in workflow
assert "version: '10'" in workflow
assert '["pnpm", "install", "--frozen-lockfile"]' in validator
assert '["pnpm", "typecheck"]' in validator
assert '["pnpm", "build"]' in validator

print("tool_missing() checks executable presence only: PASS")
print("CI declares Node major 24 and pnpm major 10: PASS")
print("validator runs install, typecheck, and build through pnpm: PASS")
PY

printf '%s\n' '--- available local tool versions ---'
for tool in node pnpm; do
  if command -v "$tool" >/dev/null 2>&1; then
    "$tool" --version
  else
    printf '%s unavailable\n' "$tool"
  fi
done

Repository: Lyellr88/marm-memory

Length of output: 543


Require the CI toolchain before returning SAFE.

tool_missing() checks only executable presence. Require Node 24 and pnpm 10, matching .github/workflows/console.yml, before running the build. Otherwise, the validator can report SAFE with a toolchain that differs from CI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-console-pr.py` around lines 52 - 53, Update tool_missing() to
validate the installed Node and pnpm versions in addition to executable
presence, requiring Node 24 and pnpm 10 to match .github/workflows/console.yml.
Ensure mismatched or unavailable versions are reported as missing before the
validator can return SAFE, while preserving checks for gh and git.

Source: Path instructions

Comment thread scripts/check-console-pr.py Outdated
Comment thread scripts/check-console-pr.py Outdated
Comment thread scripts/check-console-pr.py Outdated
The new Python job failed on its first run: 12 errors against a baseline of 2.
The baseline was recorded on Windows and CI is Linux, and two separate things
made the counts diverge.

Platform narrowing. mypy narrows platform on sys.platform and not on os.name,
so `if os.name == "nt"` branches were analyzed on Linux, where
subprocess.CREATE_NEW_PROCESS_GROUP and DETACHED_PROCESS do not exist. Switched
the two guards that gate those flags. Equivalent at runtime.
_set_windows_owner_only_dacl had no platform guard of its own and dereferences
ctypes.WinDLL, so it now returns False off Windows rather than relying on its
caller's check; a direct call elsewhere would have raised AttributeError.

Missing stubs. types-psutil is declared in the dev extra, but both workflows
install their test tools explicitly and never picked it up, so psutil resolved
to Any in CI and produced three import-untyped errors plus a no-any-return.
Added to both install lines.

mypy now reports the same 2 errors natively and under --platform linux, so the
baseline means the same thing on a developer machine and on the runner.

runtime_manager.py:370 keeps os.name deliberately: its branches are valid on
both platforms and its SIGKILL ignore depends on mypy checking the else branch.
_Watched.last_full started at 0.0 and is compared as
`monotonic() - last_full < GRAPH_AUTO_INDEX_FULL_INTERVAL`. monotonic() counts
from boot, so 0.0 reads as "indexed at boot" rather than "never indexed": on a
machine up for less than the 300s interval, a non-git project's first index
waited the interval out instead of running immediately. float("-inf") states
"never" in the same units the comparison uses.

Found by the new Python CI job, which failed five tests in
test_graph_auto_index.py that pass locally. They were not asserting anything
wrong; their outcome depended on the host's uptime, verified directly:

  monotonic()=12s   -> reindexed=[]                  (fresh CI runner)
  monotonic()=299s  -> reindexed=[]
  monotonic()=301s  -> reindexed=['non_git_interval']

The release workflow hid this. It spends minutes on model bundling, a pnpm
install, a console build, and a Docker build before pytest, so the runner was
always past 300s uptime by then. The new job installs and tests directly, which
starts pytest early enough in the VM's life to expose it. Not a regression from
the v2.38.0 typing pass, which touched this file for annotations only.
@Lyellr88

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Lyellr88 and others added 3 commits August 13, 2026 20:50
Concurrency keyed on the PR number rather than head_ref. Two PRs from
different forks can both use a branch named `main`, and a shared group means
one cancels the other's required check, leaving that PR blocked with nothing
to report.

persist-credentials: false on both checkouts. The console job runs pnpm
install on a PR-controlled lockfile, which executes lifecycle scripts, and the
default leaves the job token in .git/config where they can read it. Both jobs
pass GH_TOKEN to gh explicitly, so detection is unaffected.

Pin mypy, types-psutil, and ruff in the dev extra to the versions the gates
pin. The extra floored them, so `pip install -e ".[dev]"` resolved a different
checker than CI and than the one that set BASELINE. Ruff was the same defect
already observed live: 0.16.2 promoted RUF036 out of preview and failed a PR
whose code had not changed while local 0.15.16 called it clean.

check-console-pr.py: a PR with no merge ref no longer reports SAFE after its
head builds, scratch refs move to refs/console-check/ and cleanup deletes only
the ones the run created (it force-deleted the whole namespace, including a
developer's own branches), and the baseline fetch result is checked so a failed
fetch cannot build against a stale base and report the drift as PR breakage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ess call

No behavior change; False is the default. The helper reads returncode itself,
so saying so silences PLW1510 when ruff is run from the repo root.

Root-level ruff is not a CI gate: both ruff jobs scope to marm-mcp-server, and
the root scripts/ tree carries 117 findings on MARM-main that nothing scans.
Untouched here rather than swept into a CI PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three defects in the doc mirror path, all found by review of the v2.38.0 fix
and each reproduced by a failing test before being changed.

Resolve by doc_id whenever the linked id fails to match a row, not only when
the caller passed none. A non-null but deleted docs.memory_id skipped the
lookup, so a doc that already carried duplicates gained a third row on the
next save.

Order that resolve by id rather than timestamp. The write rewrites the
timestamp it was ordering on, so each save picked whichever duplicate it had
not just touched; with a link that kept failing, saves alternated between two
rows indefinitely and neither ever held current content. id never changes.

Report the mirror row that was written, not the doc's stored link, whenever a
row exists. Both pending causes reported the link, which was correct while
pending only meant the mirror write failed and no row existed. Now that a
written mirror can go unlinked, that answer returns null or a deleted id at
exactly the moment a real mirror is sitting there orphaned. Null now means only
that the mirror write itself failed.

Pre-existing duplicates are still not removed. Deleting them takes their
chunks, queue entries, and concept provenance with them, which is a migration
and not done silently; saves now converge on one of them instead of spreading
across them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

The v2.38.0 entry covered the doc mirror work but not the auto-index bug that
shipped alongside it: a never-indexed project waited out the full 300s interval
before its first index whenever the host had been up for less than that, because
the "last indexed" marker started at 0.0 and time.monotonic() counts from boot.
Fresh containers and just-rebooted machines were affected.

Developer notes gain the platform-independent type baseline, the dev extra now
pinning mypy, its stubs, and Ruff to the gate versions rather than flooring them,
and pull requests now building the Console and running the Python suite instead
of leaving both to a version tag.

No version bump: v2.38.0 is merged and untagged, so this folds into it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Lyellr88
Lyellr88 merged commit 946b39c into MARM-main Aug 14, 2026
9 checks passed
@Lyellr88
Lyellr88 deleted the chore/ci-depth branch August 14, 2026 03:15
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