Repository navigation
chore(OMN-15989): make .onex_state disposable-by-default with two named durable subtrees - #1609
Merged
github-actions[bot] merged 1 commit intoAug 28, 2026
Conversation
…ed durable subtrees The teardown-blocking class this closes: an untracked, regenerable artifact under a worktree's own .onex_state/ leaves a landed, 0-ahead/0-behind worktree dirty, and a dirty worktree escalates removal into a per-incident owner-approval gate. Six omnibase_core worktrees are blocked that way right now (OMN-16177/16346/16507/16589/16625/16677), none of them by real work. The rule replacing the per-file judgement call: inside a repo checkout, .onex_state/ is DISPOSABLE; the only durable content is the two named subtrees .onex_state/evidence/ and .onex_state/friction/, which stay visible to git status. State that must outlive the checkout lives outside every worktree at $OMNI_HOME/.onex_state/ (lane scratch, ledger locks, claim/run state), which nothing here can reach. The pattern is .onex_state/* plus two negations, not .onex_state/ -- git cannot re-include a path whose parent directory is excluded, so the directory form would make the negations dead. The three explicit consumer-graph lines from OMN-15431 are subsumed by the top-level rule; their rationale is kept in the comment. Test names the line on both sides and carries a negative control asserting src/, tests/, docs/ and .gitignore itself are never swallowed. Its git call is env-scrubbed per OMN-14891.
Contributor
|
Warning Review limit reachedNext included review available in 49 minutes. View limit detailsLimit details: You’ve used the included review currently available. Your 132 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
jonahgabriel
pushed a commit
to OmniNode-ai/onex_change_control
that referenced
this pull request
Aug 28, 2026
…#7469) * evidence: OCC companion pass 1 for OmniNode-ai/omnibase_core#1609 * evidence: OCC companion self-bind for #7469 --------- Co-authored-by: node-occ-companion-effect <occ-companion-effect@omninode.ai>
github-actions
Bot
deleted the
jonah/omn-15989-onex-state-disposable-rule
branch
August 28, 2026 22:41
4 of 5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
OMN-15989 —
.onex_state/is disposable by default, with two named durable subtreesThis is the second of two surfaces for OMN-15989. The first,
omniclaude#2061, merged 2026-08-28T19:45:16Z and taught the canonical teardown tool (scripts/prune-worktrees.sh) the same rule. This PR writes the rule into the repo where the failure was actually observed, so it applies atgit statustime rather than only at teardown time.Premise check first — the ticket's example was stale, its mechanism was not
The ticket cites
.onex_state/consumer-graph.json. That file was already gitignored here by OMN-15431 (merged4831d76, 2026-08-01) — twelve days before the ticket was filed — and the ledger line it cites (docs/tracking/2026-07-09-codex-merge-controller-ledger.md:4776) does not exist; that file is 2258 lines. Recorded on the ticket before any code was written.The failure class is live. A bounded scan (1037 worktrees enumerated via
git worktree list --porcelainacross every canonical clone, narrowed to those holding a.onex_state/dir, thengit status --porcelain --untracked-files=allon each) finds six worktrees dirty solely from untracked.onex_statescratch, with zero non-.onex_statedirt — all of them in this repo:.onex_stateentriesOMN-16177/omnibase_corepush_exit_code.txt,push_log.txtOMN-16346/omnibase_coreMOVED_TO_201.md,omn16346-prepush-waiter.sh,.outOMN-16507/omnibase_coreMOVED_TO_201.md,omn16507-prepush-waiter.sh,.outOMN-16589/omnibase_coreMOVED_TO_201.mdOMN-16625/omnibase_coreMOVED_TO_201.mdOMN-16677/omnibase_coreOMN-16677-push-handoff.mdEach one turns teardown into a per-incident owner-approval decision about a file a command can rewrite. Not one of them is real work.
The rule (AC1)
The rule ships as prose next to the patterns, and a test asserts it stays there — a bare pattern block with the rationale stripped is how the separation decays back into per-file judgement.
Both sides of the line, named (AC2)
The durable side is not a guess:
git ls-tree -r --name-only origin/dev -- .onex_statereturns exactly 7 paths, and every one is underevidence/orfriction/.Durable — stays visible to
git status:.onex_state/evidence/**(6 tracked files) and.onex_state/friction/**(1 tracked file).Disposable — ignored: everything else at
.onex_state/*. Observed instances:consumer-graph.json/.lock/.json.*.tmp(OMN-15431),push_log.txt,push_exit_code.txt,MOVED_TO_201.md,*-prepush-waiter.sh/.out,OMN-16677-push-handoff.md, plus nested per-run output (local_runtime/,tmp/,lane_scratch/).The three
consumer-graphlines are replaced, not dropped —.onex_state/*is a strict superset of them. Their OMN-15431 rationale is folded into the new block.Shape:
.onex_state/*then!.onex_state/evidence/+!.onex_state/friction/. The/*form is load-bearing and commented in place: ignoring.onex_state/outright excludes the directory itself, and git cannot re-include a path whose parent directory is excluded, which would make both negations dead.TDD, red first
tests/validation/test_onex_state_disposable_gitignore.pydrives realgit check-ignore --no-indexagainst this repo's real.gitignore—--no-indexbecausecheck-ignoreotherwise refuses to report a tracked path as ignored, which would make the durable-side assertions pass for the wrong reason. The env is scrubbed viascrub_git_location_env(OMN-14891) so a hook-contextGIT_DIRcannot silently retarget another repo.RED (
.gitignorereverted toorigin/dev, final test file): 8 failed, 12 passed. Every failure is a live artifact from the table above, plus the written-down-rule assertion. The 12 passes are correct: 3 consumer-graph paths were already covered by OMN-15431, and the durable + negative-control cases must pass on both sides of the fix.GREEN (
test_onex_state_disposable_gitignore.py+ both pre-existingtest_gitignore_baseline*.py): 41 passed — 20 new, 21 pre-existing baseline tests unchanged.Live end-to-end proof (AC3 / AC4 / AC5)
Three throwaway detached worktrees off this repo, identical disposable artifacts in each, using the real names observed above:
.gitignoregit status --porcelaingit worktree remove(no--force)origin/devcontains modified or untracked files— still on disksrc/omnibase_core/__init__.pyM src/omnibase_core/__init__.py)beforeandafterdiffer only in the.gitignore, which makes the rule the demonstrated cause rather than a correlate. Thenegativerow is the guard the ticket asks for: this must never widen into a mask over unpushed work. A parametrised negative control in the test file covers the same ground statically oversrc/,tests/,docs/, and.gitignoreitself.Shared location, not per-machine (AC6)
The rule lives in the tracked
.gitignoreand in the trackedscripts/prune-worktrees.sh— never in.git/info/excludeor acore.excludesFile, so it travels with the clone and cannot diverge per machine by construction.One correction to the ticket's wording: it asks to "verify on both
.200and this Mac." This Mac is.200(ipconfig getifaddr en0→192.168.86.200, hostnameStickybeatz-Studio.local), so that is one host, not two. Being tracked repo content, the rule is machine-independent by construction rather than by two-host testing; the honest statement is that the two-host check is not available to be run, not that it passed.Known limit, stated rather than papered over
A
.gitignorecannot retroactively clean a worktree that already exists — a worktree checks out its own branch's.gitignore, so this rule is absent from the tree of any worktree branched before it merges. The six worktrees above are unblocked by the already-mergedomniclaude#2061teardown-tool half, not by this PR. This PR closes the class going forward. That division is why the ticket's AC6 permits either surface and this ticket landed both.Local verification
ruff format(unchanged),ruff check(all passed),mypy(no issues) on the new test. Governed pre-push selector ran on push — no override flag, no--no-verify, no bypass.Ticket: OMN-15989
Evidence-Ticket: OMN-15989
Evidence-Source: OCC#7469