Skip to content

Make .gitignore actually implement its own stated policy - #939

Merged
loganfinney27 merged 2 commits into
mainfrom
claude/gitignore-qzt7le
Aug 10, 2026
Merged

loganfinney27 merged 2 commits into
mainfrom
claude/gitignore-qzt7le

Conversation

@loganfinney27

@loganfinney27 loganfinney27 commented Aug 9, 2026 •

Copy link
Copy Markdown
Member

AGENT PR TEMPLATE

Agent: Claude Code (agent:claude-code)
Date: 2026-08-09
Branch: claude/gitignore-qzt7le → main


Correction. An earlier version of this body presented the 4-line .gitignore as collateral damage from the same push that discarded #913/#918. That framing was wrong. 3591a4bb is authored by you, message "Simplify .gitignore: track by default, ignore only secrets and exhaust" — a deliberate simplification that happened to ride along on the push that reset logan/obsidian. Two separate things in one commit. I conflated them.

This PR is not a restore and not a revert. It does not bring back the 509-line file.


The defect

The file states a policy and does not implement it. Its only pattern is !**.md — a negation with nothing before it to negate:

$ git check-ignore --no-index .env .mcp.json .claude/.credentials.json \
    .codex/auth.json .ssh/id_ed25519
(no output)

Nothing is ignored. "Ignore only secrets and exhaust" currently ignores neither. A stray .env or a copied auth.json is picked up by git add -A with nothing to stop it.

Your policy text is kept verbatim. Only the implementation is added.

The tension you should rule on

b52b1e585 — "Retire the specimen-path gitignore assertions; keep the real questions" — retired 24 hardcoded paths on the grounds that "an enumeration of one day's junk drawer is a ratchet, not a policy." That ruling is one day old and it points at this PR.

My argument for why this is not that ratchet: those were specimens (individual salvage paths, one line per file, re-firing whenever a file moved). These are patterns — *.pem, *.env, **/node_modules/** — which do not grow when a new file appears and do not care where anything moves. A pattern set is what "ignore secrets and exhaust" means mechanically; there is no way to ignore secrets without naming their shapes.

But it is 152 lines, and you just ruled in the direction of less. If you want the secrets half only — drop the entire exhaust section, ~60 lines — say so and I'll cut it. Exhaust is untidiness; secrets are the part with consequences.

Two git rules that make the obvious spelling wrong

1. Git does not descend into an excluded directory, so a later ! cannot rescue a file inside one. node_modules/ followed by !**/*.md loses the markdown silently. Exhaust is therefore dir/** plus !dir/**/, which keeps git descending so the markdown re-include applies. 49 markdown files are tracked inside node_modules.

2. A pattern containing a slash is anchored to this directory. node_modules/** matches only a root copy; THE-GEMSTONE/node_modules/ escapes it. My first draft had this bug; the test below caught it. Tool dirs now use **/; names that are also ordinary vault folders (build, dist, logs, tmp, .cache — 83 tracked files live under such paths) stay root-anchored with a leading /.

Verification

category result
Secrets 11/11 ignored (was 0/11)
Exhaust ignored at any depth, incl. nested node_modules
Markdown NOT ignored anywhere, incl. inside exhaust dirs
Vault folders notes/logs/, project/build/, vault/tmp/ still tracked
Tracked count 38,480 before and after — nothing untracked
tests/test_dotfolder_gitignore_policy.py passes — .claude/CLAUDE.md, .codex/AGENTS.md, .config/CONFIG.md all visible

--no-index matters: without it an already-tracked file always reports as not-ignored, which makes a broken pattern look like it works. That is how the current file's emptiness stayed invisible.

The 11 tracked files that match a rule are unaffected — git never ignores a tracked file — but named rather than left as a number: ten .log files, and .factory/certs/factory-ai-root.pem, which is a public root certificate, not a private key. No live secret exposure in the tracked set.

Blockers


Checklist:

  • Tests pass — tests/test_dotfolder_gitignore_policy.py passes against this file (run locally; main now carries pytest in uv.lock, so it runs in CI too).
  • No secrets in diff — the diff adds secret patterns; it contains no secret values.
  • Documentation updated IF needed — the two git rules are documented in the file, beside the patterns they explain.
  • Reviewer assigned — Logan.

Risk Level:

  • LOW: Single file fix, non-critical
  • MEDIUM: Multiple files, standard operation
  • HIGH: Core changes, requires human eyes

One file, but a wrong pattern here hides content silently rather than loudly. Nothing is untracked and markdown is verified unignorable; the judgement calls worth your eyes are the root-anchoring of build/dist/logs/tmp, and whether the exhaust section should exist at all given b52b1e585.


Labels to apply:

  • agent:claude-code

https://claude.ai/code/session_01EBV6TkrwsZhcwkh1b6NUHs

The header says the vault tracks by default and ignores only secrets and
exhaust. The file did not do that. It carried one pattern — `!**.md`, a
negation with nothing to negate — so it ignored nothing at all:

    $ git check-ignore --no-index .env .mcp.json .claude/.credentials.json \
        .codex/auth.json .ssh/id_ed25519
    (no output)

The policy text is kept verbatim. Only the implementation is added.

Shape notes, because two git rules make the obvious spelling wrong:

- Git does not descend into an excluded DIRECTORY, so a later `!` cannot
  rescue a file inside one. `node_modules/` followed by `!**/*.md` loses
  the markdown silently. Exhaust is therefore written `dir/**` plus
  `!dir/**/`, which keeps git descending and lets the markdown
  re-include at the bottom actually work. 49 markdown files are tracked
  inside node_modules today.

- A pattern containing a slash is anchored to this directory, so
  `node_modules/**` matches only a root copy and `THE-GEMSTONE/node_modules/`
  escapes it. Unambiguous tool directories get a `**/` prefix. Names that
  are also ordinary vault folders (build, dist, logs, tmp, .cache — 83
  tracked files live under such paths) stay anchored at the root with a
  leading `/`, because track-by-default means a note folder named `logs`
  is content, not exhaust.

Verified with git check-ignore --no-index, not by reading:

  secrets      11/11 now ignored (was 0/11)
  exhaust      ignored at any depth, including nested node_modules
  markdown     NOT ignored anywhere, including inside exhaust dirs
  vault dirs   notes/logs/, project/build/, vault/tmp/ still tracked
  tracked      38,480 files before and after; nothing untracked

11 tracked files match an ignore rule and are unaffected (tracked files
are never ignored): ten .log files, and .factory/certs/factory-ai-root.pem,
which is a public root certificate rather than a private key.

Context: the 4-line version arrived in 3591a4b (+3 -507), the same push
that discarded the #913 and #918 merges from logan/obsidian.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBV6TkrwsZhcwkh1b6NUHs
Copilot AI balanced review requested due to automatic review settings August 9, 2026 20:10
@tenki-reviewer

tenki-reviewer Bot commented Aug 9, 2026

Copy link
Copy Markdown

Insufficient balance to process this code review. Please add funds or upgrade your plan in billing.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copilot AI 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.

Copilot wasn't able to review any files in this pull request.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@qodo-code-review

Copy link
Copy Markdown
Contributor

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@sourcery-ai

sourcery-ai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

.gitignore is updated to actually implement the stated "track markdown, ignore secrets and exhaust" policy, with carefully scoped ignore patterns that avoid accidentally dropping markdown or vault content while ignoring common secret and build/exhaust files and directories at appropriate depths.

File-Level Changes

Change Details Files
Implement the repository-wide ignore policy in .gitignore while preserving markdown tracking and avoiding unintended vault-folder ignores.
  • Replace the ineffective !**.md-only .gitignore with a set of patterns that explicitly ignore common secret files and directories (e.g., .env variants, credentials, keys, tokens, AWS credentials).
  • Add patterns to ignore typical tool, cache, and build/exhaust directories at any depth (e.g., **/node_modules/**, **/__pycache__/**, **/.venv/**, **/.pytest_cache/**, and similar), using **/ forms to ensure nested tool directories are covered.
  • Anchor certain generic folder names (e.g., /build/**, /dist/**, /logs/**, /tmp/**, /.cache/**) to the repository root so same-named note/vault subfolders deeper in the tree remain tracked content.
  • Include documentation comments directly in .gitignore explaining Git’s directory-descend and slash-anchoring rules and why the patterns use dir/** vs **/dir/** for different cases.
  • Verify via git check-ignore --no-index that secrets and exhaust are ignored, markdown is never ignored (even inside ignored directories), vault folders remain tracked, and the tracked-file count is unchanged.
.gitignore

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@loganfinney27, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9d481dca-3c0f-4cb5-8b43-f6173f682354

📥 Commits

Reviewing files that changed from the base of the PR and between 2de9687 and ab680cb.

📒 Files selected for processing (1)
  • .gitignore

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.

@loganfinney27 loganfinney27 added the risk/med Filetype: med (computer code — executes). label Aug 9, 2026

@sourcery-ai sourcery-ai 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.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@tenki-reviewer

tenki-reviewer Bot commented Aug 9, 2026

Copy link
Copy Markdown

Insufficient balance to process this code review. Please add funds or upgrade your plan in billing.

@codacy-production

codacy-production Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Coverage ∅ diff coverage · -0.02% coverage variation

Metric Results
Coverage variation ✅ -0.02% coverage variation (-1.00%)
Diff coverage ✅ ∅ diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (2de9687) 13529 11333 83.77%
Head commit (ab680cb) 13529 (+0) 11330 (-3) 83.75% (-0.02%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#939) 0 0 ∅ (not applicable)

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@loganfinney27

Copy link
Copy Markdown
Member Author

If you are watching or subscribed to this PR, please respond to this comment.

Copy link
Copy Markdown
Member Author

Watching. Session 01EBV6TkrwsZhcwkh1b6NUHs.

State at ab680cb2. Sourcery reviewed and approved; Codacy 0 issues; tests/test_dotfolder_gitignore_policy.py passes against this file.

Waiting on you for one decision, and it's the reason I haven't pushed further: your b52b1e585 ruling — "an enumeration of one day's junk drawer is a ratchet, not a policy" — is one day old and points squarely at this PR.

My argument is that specimens grow and move while patterns don't, so *.pem isn't the same thing as 24 hardcoded salvage paths. But it's 152 lines and you just ruled toward less. Say the word and I cut the exhaust section (~60 lines), keeping secrets only.

Related: you asked what an "exhaust directory" was. That phrase was mine, not yours — I welded your noun onto a category and never checked your definition against it. The secrets half is unambiguous; the exhaust half rests on my guess at what you meant.

Also corrected here: I originally framed the 4-line .gitignore as collateral damage from the rewind. It isn't — 3591a4bb is yours, deliberate, with a clear message. This is neither a restore nor a revert; it's the narrow claim that a file saying "ignore secrets and exhaust" currently ignores nothing (0/11 → 11/11, tracked count unchanged at 38,480, markdown verified unignorable everywhere).


Generated by Claude Code


Generated by Claude Code

@loganfinney27
loganfinney27 added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 50c9d05 Aug 10, 2026
37 of 38 checks passed
@loganfinney27
loganfinney27 deleted the claude/gitignore-qzt7le branch August 10, 2026 00:56
@devactivity-app

Copy link
Copy Markdown

Pull Request Summary by devActivity

Metrics

Cycle Time: 4h 46m Coding Time: < 1 min Pickup Time: 1m Review Time: 4h 44m Comments: 7

Achievements

@github-actions github-actions Bot added the lifecycle/merged Lifecycle state: merged label Aug 10, 2026
loganfinney27 pushed a commit that referenced this pull request Aug 10, 2026
… proposal

While this branch's pattern-set proposal waited for review, Logan merged
#939 — a fuller .gitignore engineered around git's two sharp edges
(tracked files are never ignored; excluded directories swallow later
re-includes). That merge is the ruling on the pattern set, so this merge
resolves every conflict by taking main wholesale: the proposal yields to
the canon file, and the workflows, LLM-Router.md, and pyproject's
[tool.coverage.report] all come from main.

This PR's diff against main is empty again — its second payload landed
through another door, like its first. With auto-merge armed it now
terminates by merging as a no-op, which is this vault's lawful ending
for a PR.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fipj4vEJ5ADPuunn9ed5Hd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lifecycle/merged Lifecycle state: merged risk/med Filetype: med (computer code — executes).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants