Skip to content

mxcli fix hashes + git-state warnings for Studio Pro (#972 items 1, 3) - #973

Merged
ako merged 6 commits into
mainfrom
feat/972-fix-hashes-git-warnings
Oct 4, 2026
Merged

ako merged 6 commits into
mainfrom
feat/972-fix-hashes-git-warnings

Conversation

@ako

@ako ako commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Part of #972 — items 1 and 3. Item 2 (mx_metadata git notes) is not in this PR.

Item 1: mxcli fix hashes

  • modelsdk/mpr/contents_hash.go: Reader.VerifyContentsHashes() compares every Unit.ContentsHash with base64(SHA-256(file)) of its mprcontents/xx/yy/<uuid>.mxunit, using the writer's hash and path code. It reports MISMATCH, MISSING (indexed, no file) and ORPHAN (file, not indexed). Writer.RepairContentsHashes() rewrites the mismatched hashes and bumps _Transaction.LastTransactionID in one SQLite transaction. It takes the same guard as every write (guardWrite, the Studio Pro .mpr.lock check). The files are the source of truth and are never touched. MISSING and ORPHAN are reported only; diag --check-units --fix already removes orphans. On MPR v1 it returns ErrNotMPRv2.
  • cmd/mxcli/cmd_fix_hashes.go: mxcli fix hashes -p app.mpr [--repair], a sibling of fix widgets / fix design-properties. It exits 1 while issues remain, so it can gate CI. On MPR v1 it says the check does not apply and exits 0. Each reported line names the unit ([DomainModels$DomainModel]).
  • Warning from exec and docker check: cost measured on testapp (900 units). The whole mxcli fix hashes process takes about 0.2 s, so both commands now print a one-line warning when the hashes do not match or a unit file is missing. The warning never fails the command, and on v1 or an error it prints nothing.

Item 3: git-state warnings

  • cmd/mxcli/gitstate.go warns when the checked-out branch has no upstream (remedy git push -u <remote> <branch>, or git remote add origin <url> && … when there is no remote). It also warns on "detected dubious ownership", reusing the safe.directory command that git itself prints and telling the user to run it on the Studio Pro machine.
  • The warnings are wired into docker check, run --local and a new mxcli diag -p app.mpr project section. That section reports both the hash drift and the git state. There is no doctor command; diag is the closest one.
  • Decisions (in the code comment and the docs): the warnings never fail a command. They stay silent outside a git repo or when git is missing, and on a detached HEAD (CI and checkout <sha>, where there is no branch to push). They are also silent when $CI is set or MXCLI_NO_GIT_WARNINGS=1. Each git call has a 3 s timeout and runs with GIT_TERMINAL_PROMPT=0.
  • Caveat (documented): dubious ownership is judged by the git that mxcli runs. Inside a devcontainer the host's view can differ.

Docs

A new page, docs-site/src/tools/outside-studio-pro.md (in SUMMARY). Also short notes in docker-check.md and run-local.md, a tip in the diff-local command, and a CHANGELOG entry under Unreleased/Added. No finding was recorded because these are features, not bug fixes.

Test plan

  • go test ./modelsdk/mpr/ uses a minimal v2 harness. It covers: an untouched control is clean; a reverted file is detected; a missing file and an orphan file are reported; repair rewrites the hash and leaves the file alone; repair is refused while .mpr.lock exists and the hash is unchanged; v1 returns ErrNotMPRv2.
  • go test ./cmd/mxcli/ runs on a pedapp copy:
    • The untouched control is clean and prints no warning.
    • A unit's bytes are changed: verify exits with errHashIssuesRemain, MISMATCH names the unit, and the drift warning fires. After --repair the project is clean and the warning is gone.
    • On the v1 fixture the command reports not applicable.
  • go test ./cmd/mxcli/ with temp git repos:
    • A branch with no upstream warns, with the push remedy.
    • With no remote it warns with the add-remote remedy.
    • With an upstream it stays silent (control).
    • Outside a repo, on a detached HEAD, under CI and with the opt-out it stays silent.
    • Dubious ownership is replayed through the runner, using git's verbatim stderr.
  • End to end on a testapp copy:
    1. exec create persistent entity MyFirstModule.HashProbe, then restore the changed .mxunit bytes from a snapshot (as git checkout would).
    2. fix hashes reports 1 DomainModels$DomainModel mismatch and exits 1.
    3. --repair exits 0, and the next verify is clean.
    4. mx check (11.14.0) reports 0 errors; the untouched control copy also reports 0 errors.
    5. docker check and exec on a drifted copy in a fresh git init repo print both warnings.
  • Real dubious ownership (repo chowned to root via sudo, safe.directory override removed): mxcli diag -p printed the warning with git's own remedy line.
  • Revert checks:
    • Verify that never compares → the detection test fails ("want 1 mismatch").
    • Repair that writes no hash → the repair test fails (hash unchanged).
    • Guard removed → the Studio Pro test fails.
    • CLI repair replaced by verify → TestFixHashes_DetectsAndRepairsRevertedUnit fails.
    • gitStateWarningsWith returning nil → the no-upstream, no-remote and dubious tests fail.
    • Upstream check disabled → TestGitState_WithUpstreamIsSilent fails.
  • make build, make check-conformance, make lint, make check-findings: all pass.

Follow-ups (not done)

🤖 Generated with Claude Code

ako and others added 6 commits October 4, 2026 14:53
…ash index

Compares every Unit.ContentsHash with base64(SHA-256) of its .mxunit and
reports mismatches, missing files and orphan files; --repair rewrites the
mismatched hashes in one transaction under the writer's Studio Pro guard.
exec and docker check warn when the index disagrees (~0.2 s on 900 units).

Part of #972 (item 1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Studio Pro 11.13 fails with "Unable to find 'system' property in 'system'"
when the branch has no upstream or git reports dubious ownership. docker
check, run --local and diag -p now warn with the remedy. Never fatal;
silent outside a repo, on a detached HEAD, under CI or with
MXCLI_NO_GIT_WARNINGS=1.

Part of #972 (item 3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Part of #972.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
watchAndApply held a bare *WebClientWatcher. A bundler that exited was never
restarted, so every later page change failed with "watcher exited"; a failed
incremental build (ENOTDIR on web/pages mid-rewrite, measured on 11.13 after
adding an entity) dropped the change and the next one too; and
ensureClientServed's recovery ran a one-shot production bundle in the same
web/ directory while the watcher was still running.

bundlerSupervisor now owns the bundler: EnsureAlive restarts an exited one
with backoff, AwaitRebuild retries a failed incremental rebuild once with a
fresh bundler, and a recovery re-bundle replaces the bundler (stop and reap,
then start) instead of running beside it. The bundle-build limit is
configurable (--web-client-timeout, MXCLI_WEB_CLIENT_TIMEOUT) and a timeout
prints the tail of web-client-build.log. A change that restarts the runtime
says that browser sessions were dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After each apply watchAndApply moved its change baseline to the source's
current mtime, so an exec or save that landed during the build was folded
into the baseline and never rebuilt. Keep the baseline at the mtime the build
settled on; the build writes nothing under the watched source.

Found while reproducing #971.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ako
ako merged commit cd53ddf into main Oct 4, 2026
43 of 45 checks passed
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