sidegraph 0.17.2__tar.gz → 0.17.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/workflows/ci.yml +1 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/CHANGELOG.md +17 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/CLAUDE.md +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/PKG-INFO +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/troubleshooting.md +5 -2
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/integrations/graphify.md +14 -2
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/cli.md +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/hooks.md +7 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/package.json +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/.claude-plugin/plugin.json +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/.codex-plugin/plugin.json +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/.muse-plugin/plugin.json +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/pyproject.toml +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/__init__.py +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/cli.py +12 -6
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/githooks.py +152 -30
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/integrity.py +27 -2
- sidegraph-0.17.3/tests/githooks_legacy_helper.py +46 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/githooks_support.py +0 -21
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_githooks.py +2 -5
- sidegraph-0.17.3/tests/test_githooks_atomic_lock.py +246 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_integrity_refresh_hook.py +87 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/uv.lock +1 -1
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.agents/plugins/marketplace.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.claude-plugin/marketplace.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/CODEOWNERS +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/secret_scanning.yml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/workflows/publish.yml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/workflows/scorecard.yml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.github/workflows/session-link-gate.yml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.gitignore +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.gitleaks.toml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.opencode/INSTALL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.pre-commit-config.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/.python-version +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/AGENTS.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/CODE_OF_CONDUCT.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/CONTRIBUTING.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/LICENSE +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/README.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/SECURITY.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/README.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/concepts/anchoring.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/concepts/data-model.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/concepts/decision-memory.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/concepts/mind-model.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/concepts/retrieval.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/getting-started/bootstrap.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/getting-started/claude-code-setup.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/getting-started/codex-setup.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/getting-started/installation.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/getting-started/quickstart.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/adr-export.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/capturing-decisions.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/ci-cd-maintenance.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/health-check.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/migrating-to-0.14.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/migrating-to-0.17.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/naming-your-domains.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/retrieval-in-sessions.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/semantic-docs.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/surviving-refactors.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/team-workflow.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/using-0.15.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/using-0.16.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/guides/verifying-your-setup.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/integrations/claude-code.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/integrations/codex.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/integrations/grok.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/integrations/muse.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/integrations/opencode.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/llms.txt +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/pilot-kit/README.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/pilot-kit/corpus_fit.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/pilot-kit/judge-prompt.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/pilot-kit/questions-prompt.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/pilot-kit/rubric-template.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/configuration.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/git-bindings.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/mcp-tools.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/operations.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/releasing.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/stability.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/reference/store-format.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/docs/whitepaper/index.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/index.js +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/.mcp.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/codex/hooks.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/codex/mcp.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/hooks/hooks.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/check-plan/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/check-plan/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/compact/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/compact/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/explain-why/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/explain-why/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/heal-anchors/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/heal-anchors/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/health-check/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/health-check/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/health-check/scripts/collect.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/import-adrs/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/import-adrs/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/manage-domains/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/manage-domains/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/name-domains/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/name-domains/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/ratify-decisions/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/ratify-decisions/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/record-decision/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/record-decision/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/record-fact/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/record-fact/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/setup/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/setup/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/stats/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/stats/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/triage-drift/SKILL.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/plugin/sidegraph/skills/triage-drift/agents/openai.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/adr.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/adr_cli.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/adr_files.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/adr_identity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/anchoring.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bash_paths.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/__init__.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/apply.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/catalog.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/cli.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/integrations.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/model.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/planner.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/proof.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/review.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/bootstrap/scan.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/capture.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/config.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/delivery.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/doc_import.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/doctor.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/domain_snapshot.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/domains.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/drift_checks.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/engine/__init__.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/engine/rationale.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/engine/reader.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/freshness.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/gitenv.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/gitio.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/host/__init__.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/host/claude_settings.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/host/diagnostics.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/host/hooks.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/host/launch.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/host/mcp_entry.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/host/session_identity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/host/subagent.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/hot_index.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/importer.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/input_limits.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/maintenance.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/maintenance_clock.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/migrate.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/nearest_anchored.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/okf.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/profiles.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/redaction_scan.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/redaction_tokens.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/retrieval.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/schema.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/seed_ladder.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/server.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/stats/__init__.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/stats/model.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/stats/render.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/store.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/store_format.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/store_layout.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/store_rules.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/store_view.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/sync.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/text_paths.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/tool_rate_limit.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/validation_errors.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/verify.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/viz/__init__.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/viz/assets/vis-network.min.js +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/viz/model.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/viz/render.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/viz/template.html +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/worktree_seeds.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/src/sidegraph/write_boundary.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/__init__.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/bounded_listings_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/conftest.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/drift_checks_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/auto_policy/parity_goldens.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bitfinex_slice.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/flows/bmad/_bmad-output/planning-artifacts/architecture/cache/ARCHITECTURE-SPINE.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/flows/generic-adr/docs/adr/001-retry.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/flows/genkovich-sdd/docs/features/cache/adr/001.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/flows/spec-kit/specs/cache/plan.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/flows/superpowers/docs/superpowers/specs/2026-07-01-cache-design.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/graph.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/hosts/claude/.claude/settings.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/hosts/claude/.mcp.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/hosts/codex/.codex/config.toml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/hosts/codex/.codex/hooks/hooks.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/bootstrap/scan/docs/adr/001-safe.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/corpus/PUBLIC_CORPORA.txt +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/corpus/openspec/_provenance.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/corpus/openspec/graph.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/corpus/self-corpus/_provenance.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/corpus/self-corpus/expected/retrieval-engine-reader.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/corpus/self-corpus/graph.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/adr/0001-use-sessions.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/bmad/ARCHITECTURE-SPINE.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/bmad/tree/_bmad-output/planning-artifacts/architecture/architecture-payments-2026-07-30/.memlog.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/bmad/tree/_bmad-output/planning-artifacts/architecture/architecture-payments-2026-07-30/ARCHITECTURE-SPINE.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/bmad/tree/_bmad-output/planning-artifacts/prds/prd-payments-2026-07-30/prd.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/genkovich/0001-queue-backpressure.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/genkovich/sad.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/genkovich/tree/docs/features/payments/adr/0001-queue-backpressure.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/genkovich/tree/docs/features/payments/sad.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/genkovich/tree/docs/features/payments/spec.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/design-empty.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/design-h3-split.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/design-with-summary.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/design.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/proposal-alternatives.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/proposal.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/tree/openspec/changes/add-thing/design.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/tree/openspec/changes/add-thing/proposal.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/tree/openspec/changes/add-thing/specs/cap/spec.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/tree/openspec/changes/add-thing/tasks.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/tree/openspec/changes/archive/2026-01-01-add-thing/design.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/tree/openspec/changes/archive/2026-01-01-add-thing/proposal.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/tree/openspec/config.yaml +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/openspec/tree/openspec/specs/cap/spec.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/spec-kit/plan.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/spec-kit/tree/specs/003-payment-retries/plan.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/spec-kit/tree/specs/003-payment-retries/spec.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/superpowers/2026-07-01-example-design.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/flows/superpowers/2026-07-01-thin-design.md +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/member_names_python_graph.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/member_names_swift_graph.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/fixtures/mini_graph.json +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/graph_fixtures.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/graph_repo_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/membership_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/moved_adoption_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/opencode_plugin_runner.mjs +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/snapshot_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/store_format2_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/store_non_file_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/store_record_support.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_adr.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_adr_files.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_adr_identity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_agent_brief_manifests.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_anchor_descriptor.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_anchor_paths.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_anchoring.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_anchoring_mapping_refresh.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_anchoring_membership.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bash_paths.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_batch_panel_fixes.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_apply.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_catalog.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_cli.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_descriptor_cleanup.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_integrations.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_model.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_planner.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_proof.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_review.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_scan.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_scan_regular.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bootstrap_unanchored.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_bounded_listings.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_capture_auto_accept.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_capture_facts.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_capture_initiative.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_capture_integration.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_capture_neighbors.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_capture_propose.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_capture_redact.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_adr.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_compact.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_compact_format2.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_doctor.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_domains.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_domains_snapshot.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_graph_paths.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_import.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_init.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_init_hooks.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_okf.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_ratify.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_ratify_facts.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_stats.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_store_precedence.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_sync.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_sync_check.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_unreadable_paths.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_cli_viz.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_codex_plugin.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_command_windows.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_community_baseline.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_compact_skill.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_config.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_config_ancestor_lookup.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_config_borrowed_graph.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_corpus_expected_renders.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_corpus_self_corpus.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_coverage_telemetry_e2e.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_delivery_evidence.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_delivery_stats.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_delivery_surfaces.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_digest_integrity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doc_corpus_integration.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doc_import.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_docs_claims.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_auto_share.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_code_drift.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_dangling_supports.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_duplicate_entity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_graph_root_mismatch.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_graph_stale.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_integrity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_never_surfaced.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_record_identity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_scan.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_stale_instructions.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_unhashable_payload.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_doctor_unratified_accept.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_domain_seed_names.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_domain_snapshot_format.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_domain_snapshot_notices.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_domains.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_drift_checks.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_engine_build.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_entity_duplicate_resolution.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_entity_get_or_create_race.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_entity_twins.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_entry_point_arguments.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_env_isolation.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_fact_reachability_gate.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_file_bound_retrieval.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_flow_profile.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_format2_notices.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_git_bindings_blame.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_git_bindings_hook.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_git_bindings_provenance.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_git_env.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_git_output_utf8.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_graph_freshness.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_graphify_pin.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_health_check_skill.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hook_body_compaction.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hook_contention.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hook_failure_diagnostics.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hook_payload_encoding.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hook_showings.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hook_spawn_guard.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_agent_brief.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_agent_state.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_borrowed_graph.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_claude_settings.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_drift_nudge.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_integrity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_launch.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_pretool.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_pretool_records.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_session_key.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_session_start.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_session_start_concurrent.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_stop.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_subagent_start.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_subdirectory_launch.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_touch_events.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_host_wiring_checks.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hot_index.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hot_index_facts.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hot_index_hook.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_hot_path_imports.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_import_dry_run_preview.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_importer.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_index_journal_mode.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_integrity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_integrity_engine_version.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_integrity_replay.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_integrity_stranded.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_lazy_root.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_maintenance_clock.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_maintenance_dry_run_parity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_maintenance_plan.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_maintenance_publish.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_mcp_entry_ratify_policy.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_mcp_entry_repo_root.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_member_anchor_wiring.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_merge_matrix_format2.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_migrate.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_mind_model_additive_fields.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_muse_plugin.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_nearest_anchored.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_okf.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_opencode_plugin.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_openspec_profile.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_pathless_descriptor_adoption.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_pilot_kit_corpus_fit.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_portable_json.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_private_tests_isolation.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_proposal_lifecycle.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_public_hook_launch.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_ratify_listing_gone_dark.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_ratify_policy.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_rationale_compatibility.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_community_labels.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_doc_nodes.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_engine_version.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_file_labels.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_graph.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_integration.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_label_conventions.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_member_name_lookup.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_member_names.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_nodes_in_file.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_perf.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_rationale.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_read.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_resolve.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_stub_collapse.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_subdir_mismatch.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_type_split.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_reader_version.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_readers_format2.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_rebuild_instruction.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_redaction_scan.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_redaction_seeded.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_redaction_tokens.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_repo_relative_paths_portable.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_repoint_integration.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_budget_counters.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_context.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_drift_marker.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_drilldown.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_facts.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_guessed.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_ids.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_integration.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_membership_generations.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_membership_index.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_rank.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_seeds.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_shown_ids.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_terminal_evidence.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_thin_tools.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_toc.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_toptier.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_retrieval_unratified.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_schema_descriptor.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_schema_domain.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_schema_fact.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_capture_diagnostics.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_capture_limits.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_cli_diagnostics.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_doc_limits.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_input_limits.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_mcp_write_diagnostics.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_numeric_enums.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_python_shapes.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_redaction_cursor.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_validation_errors.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_security_write_boundary.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_seed_ladder.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_seed_paths_portable.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_add_anchors.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_anchoring.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_annotations.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_argument_names.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_borrowed_graph.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_capture.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_commit_hint.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_coverage_events.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_decision_listing.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_domains.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_drilldown.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_facts.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_find_entity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_get_store.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_get_task_context.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_graph_freshness.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_graph_path.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_import.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_invocation_policy.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_mcp_smoke.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_nearest_anchored.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_prewrite_anchor_validation.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_ratify_facts.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_record_types.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_redaction.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_refresh.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_render_events.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_result_contract.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_supersede.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_sync_anchors.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_telemetry.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_thin_tools.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_tolerant_seeds.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_server_verify.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_session_attribution.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_skill_frontmatter.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_stats_graph.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_stats_health.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_stats_model.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_stats_render.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_stats_skill.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_stats_snapshot.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_stop_hot_path.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_stop_rearm.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_agent_state.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_atomic_write_tmp_names.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_bad_file.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_binding_index.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_canonical_stat.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_compact.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_coverage_telemetry.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_cross_process_mutations.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_derived_community.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_domain_members.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_domains.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_entities.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_fact_cascade.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_facts.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_file_anchor_names.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_format.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_format2_load.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_format2_marker.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_format2_writes.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_git_root_symlink.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_inventory.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_meta.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_migration.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_mutation_guard.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_mutation_immediate.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_non_file_entries.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_opens_with_merged_duplicate.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_persistence.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_ratification.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_rebuild_atomicity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_record_identity.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_record_types.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_render_events.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_requirement.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_retrieval.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_rules.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_slug_conflicts.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_snapshot_wiring.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_stamping_marker.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_symlinks.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_telemetry.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_threading.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_tmp_sweep_age.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_store_update_meta_if.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_subagent_start_manifests.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_subprocess_text_encoding.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_canonical_writes.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_clean.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_domains.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_drift_cache.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_fresh_clone.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_integration.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_membership.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_moved_adoption.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_rebind.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_repoint.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_report_has_findings.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_run.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_snapshot_membership.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_toc_cache.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_volatile_heal.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_sync_wiring.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_telemetry_retention.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_text_paths.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_verify_domain_snapshot.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_verify_format2_against.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_verify_format2_snapshot.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_verify_git_framing.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_verify_git_revisions.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_verify_git_stdin.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_verify_snapshot.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_verify_transitions.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_viz_asset_packaged.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_viz_model.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_viz_render_html.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_viz_render_json.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/test_worktree_seeds.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/wheel_server_trace.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tests/wheel_smoke.py +0 -0
- {sidegraph-0.17.2 → sidegraph-0.17.3}/tools/check_no_session_links.py +0 -0
|
@@ -201,6 +201,7 @@ jobs:
|
|
|
201
201
|
tests/test_hot_index_facts.py `
|
|
202
202
|
tests/test_delivery_evidence.py tests/test_delivery_stats.py tests/test_delivery_surfaces.py `
|
|
203
203
|
tests/test_git_output_utf8.py `
|
|
204
|
+
tests/test_githooks_atomic_lock.py::test_windows_pid_probe_is_never_a_signal_from_python `
|
|
204
205
|
tests/test_health_check_skill.py `
|
|
205
206
|
$privateTests
|
|
206
207
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
@@ -7,6 +7,23 @@ interfaces, exactly, and what each one promises: [`docs/reference/stability.md`]
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.17.3] — 2026-10-26
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Graph refresh hooks acquire both the runner lock and stale-breaker gate with exclusive
|
|
15
|
+
shell PID files. Concurrent hooks remain serialized on systems whose external `mkdir`
|
|
16
|
+
can report success to two racing callers, while live legacy directory locks are respected.
|
|
17
|
+
- Installer cleanup coordinates with the same breaker gate and preserves a lock whose owner
|
|
18
|
+
changed during its PID check. Optional native-lock failures no longer prevent publishing
|
|
19
|
+
an updated helper, and a failed gate PID write no longer leaves a permanent gate.
|
|
20
|
+
- Doctor detects the complete older directory-lock helper; plain `sidegraph-init` repairs
|
|
21
|
+
it while keeping hook bytes and the recorded choice. Automatic detection conservatively
|
|
22
|
+
preserves unfamiliar scripts and quoted examples. Run `sidegraph-init` after upgrading
|
|
23
|
+
in each clone that uses the old helper.
|
|
24
|
+
- Native Windows installer cleanup leaves PID-bearing locks untouched, instead of using
|
|
25
|
+
Python signal probes on process ids from a potentially different POSIX-shell namespace.
|
|
26
|
+
|
|
10
27
|
## [0.17.2] — 2026-10-25
|
|
11
28
|
|
|
12
29
|
### Fixed
|
|
@@ -13,7 +13,7 @@ task-aware retrieval + decision memory riding on the engine's entity graph.
|
|
|
13
13
|
continuing participant in the project. A core feature must preserve, organize, or deliver
|
|
14
14
|
accumulated project understanding. Document search by itself is not the product.
|
|
15
15
|
|
|
16
|
-
Sidegraph is pre-1.0 (v0.17.
|
|
16
|
+
Sidegraph is pre-1.0 (v0.17.3) — the full loop (capture, ratification, mistakes-first
|
|
17
17
|
retrieval, refactor-surviving re-anchoring, semantic docs layer, mind-model domains, and the
|
|
18
18
|
facts evidence layer) ships and is exercised end-to-end, but interfaces may still move before
|
|
19
19
|
a stable release. See
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sidegraph
|
|
3
|
-
Version: 0.17.
|
|
3
|
+
Version: 0.17.3
|
|
4
4
|
Summary: Own the memory, rent the graph — a durable decision/lessons layer as a sidecar over a code-graph engine.
|
|
5
5
|
Project-URL: Homepage, https://github.com/SantyagoSeaman/sidegraph
|
|
6
6
|
Project-URL: Repository, https://github.com/SantyagoSeaman/sidegraph
|
|
@@ -222,8 +222,11 @@ entity file is skipped, an anchor to the same name mints a second entity; once t
|
|
|
222
222
|
|
|
223
223
|
### refresh-helper-outdated
|
|
224
224
|
|
|
225
|
-
A git hook runs
|
|
226
|
-
|
|
225
|
+
A git hook runs an older graph refresh helper that uses directory-based locking, or starts
|
|
226
|
+
Graphify without `GRAPHIFY_NO_AUTO_REFRESH=1`.
|
|
227
|
+
The directory lock can admit overlapping rebuilds with uutils `mkdir`; the replacement uses
|
|
228
|
+
exclusive PID files for both the runner lock and the stale-breaker gate.
|
|
229
|
+
Graphify 0.9.87 and later refresh the agent skills they installed,
|
|
227
230
|
such as `~/.claude/skills/graphify/`, on the first run after a Graphify upgrade unless that
|
|
228
231
|
variable is set. One hook that runs the helper is enough for the check to fire, and a recorded "no"
|
|
229
232
|
does not silence it. Run `sidegraph-init` with no flag: it rewrites the helper and keeps your
|
|
@@ -242,13 +242,25 @@ the `/graphify` skill's `--update` form).
|
|
|
242
242
|
[above](#linked-worktrees-read-the-main-checkouts-graph)), so a commit in one does nothing.
|
|
243
243
|
Rebuilding there as well costs about 18 MB and 43 s for a cold build on one field corpus with
|
|
244
244
|
25 worktrees, and agents commit in worktrees constantly.
|
|
245
|
-
- **In the background, one at a time.** Git never waits for the rebuild.
|
|
245
|
+
- **In the background, one at a time.** Git never waits for the rebuild. An exclusively created PID file keeps
|
|
246
246
|
one rebuild running; a hook that fires while it runs makes it go once more when it finishes, so
|
|
247
247
|
the graph never settles on a tree older than the last request. A lock left by a job that died
|
|
248
248
|
is detected and cleared: by its pid, or, when the job died before writing one (a full disk, a
|
|
249
|
-
quota), by its age, ten minutes. `sidegraph-init --hooks`
|
|
249
|
+
quota), by its age, ten minutes. Re-running `sidegraph-init --hooks` refreshes the helper and clears a dead lock;
|
|
250
|
+
a fresh lock without a PID is kept until the ten-minute grace period expires. One risk
|
|
250
251
|
remains: after a reboot a pid can belong to a live, unrelated process, and the hook then waits
|
|
251
252
|
until that process exits.
|
|
253
|
+
Plain `sidegraph-init` also repairs an outdated helper in use, keeping the recorded choice.
|
|
254
|
+
Older helpers used lock directories; the new helper respects a live old runner and can
|
|
255
|
+
recover its stale directory. Both the lock and the stale-breaker gate now use shell
|
|
256
|
+
exclusive creation, so locking does not depend on external `mkdir`.
|
|
257
|
+
Installer cleanup takes the same breaker gate before removing a dead runner lock. A small
|
|
258
|
+
native OS lock on `sidegraph-graph-refresh.repair` serializes installers while they recover
|
|
259
|
+
a dead gate; the coordination file stays in the common git directory to keep a stable inode.
|
|
260
|
+
Where native locks are unsupported, helper publication still proceeds and optional installer
|
|
261
|
+
cleanup is skipped. On Windows, PID-bearing locks are left to the POSIX helper to recover,
|
|
262
|
+
because its PIDs need not be native Windows PIDs. Installing or repairing a helper does not
|
|
263
|
+
itself start a rebuild.
|
|
252
264
|
- **Where the output goes.** The last rebuild's output is `sidegraph-graph-refresh.log` in the
|
|
253
265
|
common git directory (`.git/` in a normal clone).
|
|
254
266
|
- **No `sidegraph-sync` in the hook.** The next memory call notices the new graph version and
|
|
@@ -1562,7 +1562,7 @@ plain-text line):
|
|
|
1562
1562
|
| `orphaned-record` | an open (`proposed`/`accepted`) decision or fact whose every Tier-2 (leaf) anchor is `orphaned`, so retrieval reaches it only through its file or domain; one finding per record, at its canonical file, naming how many leaf anchors it has. Statuses come from `index.db` and read "as of last sync", so the check is skipped while the statuses are not computed for the current graph (see *Skipped checks* below; run `sidegraph-sync`). It is the record-level view of `orphaned-binding` (any record it flags has orphaned bindings, which that code already reports), so it adds no new reason for `--check` to exit `2`. The fix is to rebuild a stale graph, then `sidegraph-sync`; otherwise re-anchor the record with `add_anchors` or the `heal-anchors` skill, or supersede it if the code is gone. Needs a usable `index.db` |
|
|
1563
1563
|
| `store-uncommitted` | store files nobody committed for at least 24 hours: records, bindings, entities, an archive segment or the root files (`format`, `.gitignore`, `stamping_live_since`) that `git status` shows as new, modified or deleted. One finding, at the store path, naming how many files there are, how old the oldest is and what kinds they are (a new `archive/` segment beside deleted records reads as "a compaction"). A new record or entity file is aged by its ULID name, which a `git stash` cannot rewrite; a modified file, or anything under `bindings/`, by its modification time; a deleted file by its subdirectory's, a lower bound. Entries fully staged in the index are not counted, so a `--check` run in a pre-commit hook does not block the commit that fixes the problem. **`--check` exits `2` on it.** The fix is to commit the store in a pull request. Silent, and not run, outside a git repository, with no `git`, or when git is slower than 2 seconds |
|
|
1564
1564
|
| `plugin-off-in-subdirectories` | Claude Code sessions started below the repository root run without the Sidegraph plugin. Claude Code reads the project settings (`.claude/settings.json`) of the launch directory only, and the repository root's `.claude/settings.local.json` for every launch inside the repository; `enabledPlugins` merges key by key (user settings, then project, then local). Two problems, reported as up to two findings: (a) the plugin is enabled only in the root's `.claude/settings.json`, so every directory below the root without its own enabling settings runs without it (reported at that file); (b) nested directories with a `.claude/settings.json` or `.claude/settings.local.json` of their own that sets `enabledPlugins` and whose merge leaves the plugin off (reported at the first such directory, naming how many there are; a nested settings file without `enabledPlugins` cannot change the merge, so it is not counted). The walk covers every directory that holds a tracked file (one `git ls-files` over the index, a few tens of milliseconds on a large repository) and looks for the two settings files in each directly, so a repository that ignores `.claude/` is covered. User settings are read from `$CLAUDE_CONFIG_DIR/settings.json` when that variable is set and non-empty, else from `~/.claude/settings.json`. Silent when the plugin is not enabled for a launch at the root at all, and not run outside a git repository, with no `git`, or when `git ls-files` takes longer than 5 seconds. **`--check` exits `2` on it**, like any finding; enabling the plugin at user scope or in the root's `.claude/settings.local.json` clears it |
|
|
1565
|
-
| `refresh-helper-outdated` | a git hook runs
|
|
1565
|
+
| `refresh-helper-outdated` | a git hook runs an older graph refresh helper that uses directory-based locking (unsafe with uutils `mkdir`), or whose Graphify line lacks `GRAPHIFY_NO_AUTO_REFRESH=1` (Graphify 0.9.87 and later can rewrite installed agent skills after an upgrade). Advisory, per clone (the helper lives in `.git/hooks`); **`--check` exits `2` on it**, like any finding. One hook that runs the helper is enough, and a recorded decline does not silence it. The fix is `sidegraph-init` (no flag), which refreshes the helper and keeps a recorded hook choice. Silent outside a git repository, with no helper, or when no hook runs it |
|
|
1566
1566
|
| `engine-version` | the graph was built by a Graphify release this Sidegraph was not tested with (its `graph.graphify_version` stamp is neither absent nor in the tested set), so anchors and domains may read differently. Advisory; **`--check` exits `2` on it**, like any finding. Pin Graphify to a tested release listed under [Engine version pinning](../integrations/graphify.md#engine-version-pinning), then rebuild the graph. It also fires for a mention-edge graph (Graphify 0.9.62 or later) over a store without a minimum Sidegraph version; follow the [0.14 migration guide](https://github.com/SantyagoSeaman/sidegraph/blob/main/docs/guides/migrating-to-0.14.md). A malformed marker leaves this second case silent. Silent without a readable graph |
|
|
1567
1567
|
| `store-not-migrated` | the store uses the pre-0.17 layout (a format marker below major 2) and holds at least one record of any kind (initiatives included). One finding, at the store path, naming `sidegraph-migrate` (run on the default branch, after the team checklist in the [0.17 migration guide](https://github.com/SantyagoSeaman/sidegraph/blob/main/docs/guides/migrating-to-0.17.md)) and the `sidegraph:compact` skill. Degraded; **`--check` exits `2` on it**, like any finding. Silent on an empty store and on a store that is already format 2 |
|
|
1568
1568
|
| `maintenance-due` | a format-2 store that `sidegraph-compact` would tidy: more than 200 per-record files, or a legacy `archive/` segment it would delete, or a misplaced or duplicated shard line, or a stray shard file. `sidegraph-verify` does not report these; maintenance heals them. A segment kept because one of its lines is not safe to delete does not count. Advisory; **`--check` exits `2` on it**, like any finding. Run `sidegraph-compact` on the default branch. Silent on a store that is not format 2 |
|
|
@@ -402,6 +402,13 @@ raises costs only its own line.
|
|
|
402
402
|
> installed on the first rebuild after an upgrade. Ask the user to run `sidegraph-init`,
|
|
403
403
|
> which refreshes the helper and keeps their recorded hook choice; do not run it unasked.
|
|
404
404
|
|
|
405
|
+
A helper using the old directory-based lock is also reported: uutils `mkdir` can admit
|
|
406
|
+
overlapping rebuilds. `sidegraph-init` replaces it with exclusive PID-file locking while
|
|
407
|
+
preserving hook bytes and the recorded choice. The outdated-helper check recognizes concrete defects in simple shell helpers,
|
|
408
|
+
rather than comparing the whole template. It conservatively skips unfamiliar scripts with
|
|
409
|
+
heredocs or multiline quotes. This controls automatic defect repair; an ordinary init
|
|
410
|
+
that refreshes a fully installed hook still rewrites its managed helper.
|
|
411
|
+
|
|
405
412
|
It also sends a notice for the person. See
|
|
406
413
|
[`refresh-helper-outdated`](../guides/troubleshooting.md#refresh-helper-outdated).
|
|
407
414
|
15. **Refresh-hook line.** When no git hook keeps the graph fresh, one line tells the model to
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sidegraph",
|
|
3
3
|
"displayName": "Sidegraph",
|
|
4
|
-
"version": "0.17.
|
|
4
|
+
"version": "0.17.3",
|
|
5
5
|
"description": "Durable decision/lessons memory over your code graph — ADRs, gotchas, and constraints that survive refactors, retrieved mistakes-first.",
|
|
6
6
|
"author": { "name": "SantyagoSeaman", "url": "https://github.com/SantyagoSeaman" },
|
|
7
7
|
"homepage": "https://github.com/SantyagoSeaman/sidegraph",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sidegraph",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.3",
|
|
4
4
|
"description": "Durable decision/lessons memory over your code graph — ADRs, gotchas, and constraints that survive refactors, retrieved mistakes-first.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"skills": "./skills/",
|
|
@@ -416,11 +416,14 @@ def _hook_graph_problem(
|
|
|
416
416
|
|
|
417
417
|
|
|
418
418
|
def _refresh_outdated_helper(info: githooks.RepoInfo) -> bool:
|
|
419
|
-
"""Rewrite
|
|
419
|
+
"""Rewrite a helper in use with the old directory lock or a Graphify run without
|
|
420
420
|
``GRAPHIFY_NO_AUTO_REFRESH=1``; ``True`` when it did. The helper is per repository, so this
|
|
421
421
|
holds whatever graph the store reads; the recorded choice and the hook files are not touched.
|
|
422
422
|
see design/superpowers/specs/2026-10-14-graphify-upgrade-design.md (D7)"""
|
|
423
|
-
|
|
423
|
+
old_lock = githooks.helper_uses_directory_lock(info)
|
|
424
|
+
if (
|
|
425
|
+
githooks.helper_is_current(info) is not False and not old_lock
|
|
426
|
+
) or not githooks.helper_in_use(info):
|
|
424
427
|
return False
|
|
425
428
|
graphify = shutil.which("graphify")
|
|
426
429
|
try:
|
|
@@ -428,10 +431,13 @@ def _refresh_outdated_helper(info: githooks.RepoInfo) -> bool:
|
|
|
428
431
|
except OSError as e:
|
|
429
432
|
print(f"graph refresh hook: could not refresh the helper ({e})")
|
|
430
433
|
return False
|
|
431
|
-
|
|
432
|
-
"graph refresh hook: refreshed the helper, which
|
|
433
|
-
|
|
434
|
-
|
|
434
|
+
if old_lock:
|
|
435
|
+
print("graph refresh hook: refreshed the helper, which used directory-based locking")
|
|
436
|
+
else:
|
|
437
|
+
print(
|
|
438
|
+
"graph refresh hook: refreshed the helper, which ran Graphify without "
|
|
439
|
+
f"{githooks.GRAPH_REBUILD_ENV}"
|
|
440
|
+
)
|
|
435
441
|
return True
|
|
436
442
|
|
|
437
443
|
|
|
@@ -27,8 +27,10 @@ import shlex
|
|
|
27
27
|
import shutil
|
|
28
28
|
import stat
|
|
29
29
|
import subprocess
|
|
30
|
+
import sys
|
|
30
31
|
import tempfile
|
|
31
32
|
import time
|
|
33
|
+
from collections.abc import Iterator
|
|
32
34
|
from dataclasses import dataclass
|
|
33
35
|
from pathlib import Path
|
|
34
36
|
from typing import Literal
|
|
@@ -76,17 +78,14 @@ _GIT_TIMEOUT = 10.0
|
|
|
76
78
|
# wrote its pid; only its age says so. The helper breaks one after this long (``-mmin +10``).
|
|
77
79
|
_STALE_LOCK_SECONDS = 600
|
|
78
80
|
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# gate; before, it blocked every rebuild for good. ``@GRAPHIFY@`` is the one substitution: the
|
|
84
|
-
# path found at install time, quoted, or ''. A second amendment sets ``GRAPHIFY_NO_AUTO_REFRESH=1``
|
|
85
|
-
# on the rebuild line (design/superpowers/specs/2026-10-14-graphify-upgrade-design.md, D7).
|
|
81
|
+
# D5's want flag, stale-breaker gate and runner PID are preserved. The lock and gate
|
|
82
|
+
# now use the shell's noclobber redirection (O_EXCL), independently of external mkdir.
|
|
83
|
+
# Old directory locks are read during upgrade; fresh incomplete owners are left alone.
|
|
84
|
+
# @GRAPHIFY@ is the install-time fallback, and every rebuild disables skill auto-refresh.
|
|
86
85
|
_HELPER_TEMPLATE = r"""#!/bin/sh
|
|
87
86
|
# Installed by sidegraph-init: keeps graphify-out/graph.json current for Sidegraph.
|
|
88
87
|
# Main checkout only: a linked worktree reads the main checkout's graph. The rebuild runs
|
|
89
|
-
# in the background so git never waits. A "want" flag plus
|
|
88
|
+
# in the background so git never waits. A "want" flag plus an exclusive PID file run one rebuild
|
|
90
89
|
# at a time and never miss a request that arrives during one.
|
|
91
90
|
hook=$1; shift
|
|
92
91
|
[ "$(git rev-parse --path-format=absolute --git-dir 2>/dev/null)" = \
|
|
@@ -102,19 +101,23 @@ log=$common/sidegraph-graph-refresh.log
|
|
|
102
101
|
: > "$want" 2>/dev/null || exit 0
|
|
103
102
|
(
|
|
104
103
|
me=$(exec sh -c 'echo $PPID')
|
|
105
|
-
take() {
|
|
104
|
+
take() { (set -C; echo "$me" > "$lock") 2>/dev/null; }
|
|
105
|
+
read_pid() {
|
|
106
|
+
if [ -d "$lock" ]; then cat "$lock/pid" 2>/dev/null; else cat "$lock" 2>/dev/null; fi
|
|
107
|
+
}
|
|
106
108
|
if ! take; then
|
|
107
|
-
pid=$(
|
|
109
|
+
pid=$(read_pid)
|
|
108
110
|
if [ -n "$pid" ]; then
|
|
109
111
|
kill -0 "$pid" 2>/dev/null && exit 0 # a runner is alive; it will see $want
|
|
110
112
|
else # the owner is mid-write, or died there
|
|
111
113
|
[ -n "$(find "$lock" -maxdepth 0 -mmin +10 2>/dev/null)" ] || exit 0
|
|
112
114
|
fi
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
(set -C; : > "$lock.gate") 2>/dev/null || exit 0
|
|
116
|
+
(echo "$me" > "$lock.gate") 2>/dev/null || : # PID write failure must not leak the gate
|
|
117
|
+
[ "$(read_pid)" = "$pid" ] &&
|
|
115
118
|
{ [ -n "$pid" ] || [ -n "$(find "$lock" -maxdepth 0 -mmin +10 2>/dev/null)" ]; } &&
|
|
116
119
|
rm -rf "$lock"
|
|
117
|
-
|
|
120
|
+
rm -f "$lock.gate"; take || exit 0
|
|
118
121
|
fi
|
|
119
122
|
cd "$top" || { rm -rf "$lock"; exit 0; }
|
|
120
123
|
while :; do
|
|
@@ -466,28 +469,125 @@ def _has_graphify_hook(info: RepoInfo) -> bool:
|
|
|
466
469
|
|
|
467
470
|
|
|
468
471
|
def _lock_is_dead(lock: Path) -> bool:
|
|
469
|
-
"""Whether the helper's lock directory belongs to a job that is gone:
|
|
470
|
-
or it has no usable pid and is over ten minutes old. A pid that runs,
|
|
472
|
+
"""Whether the helper's PID file or legacy lock directory belongs to a job that is gone:
|
|
473
|
+
its pid no longer runs, or it has no usable pid and is over ten minutes old. A pid that runs,
|
|
474
|
+
even another user's, and
|
|
471
475
|
a recent pid-less lock (an owner still writing) are live. A pid can be reused by a live
|
|
472
476
|
process after a reboot, which this cannot tell from the runner."""
|
|
473
477
|
try:
|
|
474
|
-
|
|
478
|
+
before = lock.stat()
|
|
479
|
+
age = time.time() - before.st_mtime
|
|
475
480
|
except OSError:
|
|
476
481
|
return False
|
|
477
482
|
try:
|
|
478
|
-
text = (lock / "pid").read_text().strip()
|
|
483
|
+
text = (lock / "pid" if lock.is_dir() else lock).read_text().strip()
|
|
479
484
|
except OSError:
|
|
480
485
|
text = ""
|
|
481
486
|
pid = int(text) if text.isdigit() else 0
|
|
482
487
|
if pid <= 0:
|
|
483
|
-
|
|
488
|
+
dead = age > _STALE_LOCK_SECONDS
|
|
489
|
+
else:
|
|
490
|
+
if sys.platform == "win32":
|
|
491
|
+
# These are POSIX-shell PIDs. Windows kill(pid, 0) is not a liveness probe,
|
|
492
|
+
# and MSYS/native PID namespaces differ: leave recovery to the shell helper.
|
|
493
|
+
return False
|
|
494
|
+
try:
|
|
495
|
+
os.kill(pid, 0)
|
|
496
|
+
except ProcessLookupError:
|
|
497
|
+
dead = True
|
|
498
|
+
except OSError: # PermissionError: the process exists
|
|
499
|
+
return False
|
|
500
|
+
else:
|
|
501
|
+
return False
|
|
502
|
+
if not dead:
|
|
503
|
+
return False
|
|
504
|
+
# A live owner may finish and a fresh runner may acquire the path during kill(0).
|
|
505
|
+
# Under the breaker gate, only an unchanged dead owner can now safely be removed.
|
|
484
506
|
try:
|
|
485
|
-
|
|
486
|
-
except
|
|
487
|
-
return True
|
|
488
|
-
except OSError: # PermissionError: the process exists
|
|
507
|
+
after = lock.stat()
|
|
508
|
+
except OSError:
|
|
489
509
|
return False
|
|
490
|
-
return
|
|
510
|
+
return (before.st_dev, before.st_ino, before.st_mtime_ns, before.st_ctime_ns) == (
|
|
511
|
+
after.st_dev,
|
|
512
|
+
after.st_ino,
|
|
513
|
+
after.st_mtime_ns,
|
|
514
|
+
after.st_ctime_ns,
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def _remove_lock(path: Path) -> None:
|
|
519
|
+
"""Remove a PID file or legacy directory, without following a symlink."""
|
|
520
|
+
if path.is_dir() and not path.is_symlink():
|
|
521
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
522
|
+
else:
|
|
523
|
+
with contextlib.suppress(OSError):
|
|
524
|
+
path.unlink()
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
@contextlib.contextmanager
|
|
528
|
+
def _repair_guard(info: RepoInfo) -> Iterator[bool]:
|
|
529
|
+
"""Serialize installers while repairing a dead breaker gate; the OS releases on exit.
|
|
530
|
+
|
|
531
|
+
Keep the coordination file: unlinking an advisory lock lets another installer lock a
|
|
532
|
+
different inode. A busy installer skips cleanup; the one holding the guard handles it.
|
|
533
|
+
"""
|
|
534
|
+
try:
|
|
535
|
+
handle = (info.common / f"{HELPER_NAME}.repair").open("a+b")
|
|
536
|
+
except OSError:
|
|
537
|
+
yield False
|
|
538
|
+
return
|
|
539
|
+
with handle:
|
|
540
|
+
if sys.platform == "win32":
|
|
541
|
+
import msvcrt
|
|
542
|
+
|
|
543
|
+
if handle.tell() == 0:
|
|
544
|
+
handle.write(b"\0")
|
|
545
|
+
handle.flush()
|
|
546
|
+
handle.seek(0)
|
|
547
|
+
try:
|
|
548
|
+
msvcrt.locking(handle.fileno(), msvcrt.LK_NBLCK, 1)
|
|
549
|
+
except OSError:
|
|
550
|
+
yield False
|
|
551
|
+
return
|
|
552
|
+
try:
|
|
553
|
+
yield True
|
|
554
|
+
finally:
|
|
555
|
+
handle.seek(0)
|
|
556
|
+
msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1)
|
|
557
|
+
else:
|
|
558
|
+
import fcntl
|
|
559
|
+
|
|
560
|
+
try:
|
|
561
|
+
fcntl.flock(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
562
|
+
except OSError:
|
|
563
|
+
yield False
|
|
564
|
+
return
|
|
565
|
+
try:
|
|
566
|
+
yield True
|
|
567
|
+
finally:
|
|
568
|
+
fcntl.flock(handle, fcntl.LOCK_UN)
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
def _repair_dead_locks(info: RepoInfo) -> None:
|
|
572
|
+
"""Clear dead locks under the helper's own breaker gate, never from a stale snapshot."""
|
|
573
|
+
with _repair_guard(info) as held:
|
|
574
|
+
if not held:
|
|
575
|
+
return
|
|
576
|
+
gate = info.common / f"{HELPER_NAME}.lock.gate"
|
|
577
|
+
if _lock_is_dead(gate):
|
|
578
|
+
_remove_lock(gate)
|
|
579
|
+
try:
|
|
580
|
+
handle = gate.open("x")
|
|
581
|
+
except FileExistsError:
|
|
582
|
+
return # a live/fresh gate, or a legacy breaker still using a directory
|
|
583
|
+
try:
|
|
584
|
+
with handle:
|
|
585
|
+
handle.write(f"{os.getpid()}\n")
|
|
586
|
+
lock = info.common / f"{HELPER_NAME}.lock"
|
|
587
|
+
if _lock_is_dead(lock):
|
|
588
|
+
_remove_lock(lock)
|
|
589
|
+
finally:
|
|
590
|
+
gate.unlink()
|
|
491
591
|
|
|
492
592
|
|
|
493
593
|
# -- install, remove, status -----------------------------------------------------------------
|
|
@@ -499,12 +599,8 @@ def install_helper(info: RepoInfo, *, graphify: str | None) -> None:
|
|
|
499
599
|
stale-breaker gate. For a repository whose hooks call it by hand.
|
|
500
600
|
# see design/superpowers/specs/2026-10-02-graph-refresh-hook-design.md (D2, D5)"""
|
|
501
601
|
info.own_hooks_dir.mkdir(parents=True, exist_ok=True)
|
|
502
|
-
|
|
503
|
-
if _lock_is_dead(lock): # re-running --hooks is the way out of a lock a dead job left
|
|
504
|
-
shutil.rmtree(lock, ignore_errors=True)
|
|
602
|
+
_repair_dead_locks(info)
|
|
505
603
|
_publish_file(info.helper, _encode(helper_script(graphify)), 0o755)
|
|
506
|
-
with contextlib.suppress(OSError): # a stale stale-breaker's gate (D5)
|
|
507
|
-
(info.common / f"{HELPER_NAME}.lock.gate").rmdir()
|
|
508
604
|
|
|
509
605
|
|
|
510
606
|
def install(info: RepoInfo, *, graphify: str | None) -> InstallReport:
|
|
@@ -524,14 +620,15 @@ def install(info: RepoInfo, *, graphify: str | None) -> InstallReport:
|
|
|
524
620
|
|
|
525
621
|
def remove(info: RepoInfo) -> RemoveReport:
|
|
526
622
|
"""Take Sidegraph out: the block from each hook, then (once) the helper, the want flag, any
|
|
527
|
-
lock and gate, and the recorded choice. The rebuild log
|
|
623
|
+
lock and gate, and the recorded choice. The rebuild log and native repair coordination
|
|
624
|
+
file stay: unlinking that file could let simultaneous installers lock different inodes.
|
|
528
625
|
# see design/superpowers/specs/2026-10-02-graph-refresh-hook-design.md (D3)"""
|
|
529
626
|
hooks = tuple(_strip(info.own_hooks_dir / hook, hook) for hook in HOOKS)
|
|
530
627
|
helper_removed = info.helper.exists()
|
|
531
628
|
info.helper.unlink(missing_ok=True)
|
|
532
629
|
(info.common / f"{HELPER_NAME}.want").unlink(missing_ok=True)
|
|
533
630
|
for leftover in ("lock", "lock.gate"):
|
|
534
|
-
|
|
631
|
+
_remove_lock(info.common / f"{HELPER_NAME}.{leftover}")
|
|
535
632
|
record_choice(info.top, declined=False)
|
|
536
633
|
return RemoveReport(hooks, helper_removed)
|
|
537
634
|
|
|
@@ -604,3 +701,28 @@ def helper_in_use(info: RepoInfo) -> bool:
|
|
|
604
701
|
``hooks_dir`` calls it (``_runs_helper``), so a partly wired repository counts. Read-only.
|
|
605
702
|
# see design/superpowers/specs/2026-10-14-graphify-upgrade-design.md (D7)"""
|
|
606
703
|
return info.helper.is_file() and any(_runs_helper(info.hooks_dir / hook) for hook in HOOKS)
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
_DIRECTORY_LOCK = re.compile(
|
|
707
|
+
r'^\s*(?:take\(\)\s*\{\s*)?mkdir\s+(?:"\$lock(?:\.gate)?"|\$lock(?:\.gate)?)(?=\s|;|$)'
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
def helper_uses_directory_lock(info: RepoInfo) -> bool:
|
|
712
|
+
"""Recognize shipped take()/standalone mkdir acquisitions, not arbitrary shell code.
|
|
713
|
+
|
|
714
|
+
Preserve unfamiliar helpers with heredocs/multiline quotes. Known old helpers have
|
|
715
|
+
simple acquisition lines; there is no need to parse arbitrary command/argument positions.
|
|
716
|
+
"""
|
|
717
|
+
try:
|
|
718
|
+
installed = _decode(info.helper.read_bytes())
|
|
719
|
+
except OSError:
|
|
720
|
+
return False
|
|
721
|
+
if "<<" in installed:
|
|
722
|
+
return False
|
|
723
|
+
try:
|
|
724
|
+
if any("\n" in word for word in shlex.split(installed.replace("\\\n", ""), comments=True)):
|
|
725
|
+
return False
|
|
726
|
+
except ValueError:
|
|
727
|
+
return False
|
|
728
|
+
return any(_DIRECTORY_LOCK.match(line) for line in installed.splitlines())
|
|
@@ -735,7 +735,7 @@ def _detect_store_files_skipped(inputs: Inputs) -> Problem | None:
|
|
|
735
735
|
|
|
736
736
|
|
|
737
737
|
def _detect_refresh_helper_outdated(inputs: Inputs) -> Problem | None:
|
|
738
|
-
"""A hook
|
|
738
|
+
"""A hook calls a helper with directory-based locking or missing ``GRAPHIFY_NO_AUTO_REFRESH=1``
|
|
739
739
|
(an earlier ``sidegraph-init`` wrote it). Not run outside a git repository, with no helper, or
|
|
740
740
|
when no hook calls it (``refresh-hook-missing`` says that); one hook that calls it is enough,
|
|
741
741
|
so a partly wired repository and a recorded decline do not hide it. The fix is plain
|
|
@@ -751,8 +751,33 @@ def _detect_refresh_helper_outdated(inputs: Inputs) -> Problem | None:
|
|
|
751
751
|
current = githooks.helper_is_current(info)
|
|
752
752
|
if current is None or not githooks.helper_in_use(info):
|
|
753
753
|
raise _NotRun
|
|
754
|
-
|
|
754
|
+
old_lock = githooks.helper_uses_directory_lock(info)
|
|
755
|
+
if current and not old_lock:
|
|
755
756
|
return None
|
|
757
|
+
if old_lock:
|
|
758
|
+
return Problem(
|
|
759
|
+
check="refresh-helper-outdated",
|
|
760
|
+
severity="advisory",
|
|
761
|
+
summary="graph refresh helper uses directory-based locking",
|
|
762
|
+
fix="sidegraph-init",
|
|
763
|
+
line=(
|
|
764
|
+
"Sidegraph: the graph refresh helper uses directory-based locking, which can "
|
|
765
|
+
"allow overlapping rebuilds with uutils mkdir. Ask the user to run "
|
|
766
|
+
"`sidegraph-init`, which refreshes the helper and keeps their recorded hook "
|
|
767
|
+
"choice; do not run it unasked."
|
|
768
|
+
),
|
|
769
|
+
notice=(
|
|
770
|
+
"Sidegraph: the graph refresh helper uses directory-based locking, which can "
|
|
771
|
+
"allow overlapping rebuilds with uutils mkdir. Refresh it with `sidegraph-init`."
|
|
772
|
+
),
|
|
773
|
+
findings=(
|
|
774
|
+
(
|
|
775
|
+
str(info.helper),
|
|
776
|
+
"the installed graph refresh helper uses directory-based "
|
|
777
|
+
"locking; run `sidegraph-init` to refresh it",
|
|
778
|
+
),
|
|
779
|
+
),
|
|
780
|
+
)
|
|
756
781
|
return Problem(
|
|
757
782
|
check="refresh-helper-outdated",
|
|
758
783
|
severity="advisory",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""The public 0.17.2 directory-lock helper, frozen for upgrade regression tests."""
|
|
2
|
+
|
|
3
|
+
LEGACY_HELPER = r"""#!/bin/sh
|
|
4
|
+
# Installed by sidegraph-init: keeps graphify-out/graph.json current for Sidegraph.
|
|
5
|
+
# Main checkout only: a linked worktree reads the main checkout's graph. The rebuild runs
|
|
6
|
+
# in the background so git never waits. A "want" flag plus a lock directory run one rebuild
|
|
7
|
+
# at a time and never miss a request that arrives during one.
|
|
8
|
+
hook=$1; shift
|
|
9
|
+
[ "$(git rev-parse --path-format=absolute --git-dir 2>/dev/null)" = \
|
|
10
|
+
"$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)" ] || exit 0
|
|
11
|
+
case $hook in post-checkout) [ "$3" = 1 ] && [ "$1" != "$2" ] || exit 0 ;; esac
|
|
12
|
+
top=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
|
|
13
|
+
common=$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null) || exit 0
|
|
14
|
+
graphify=$(command -v graphify 2>/dev/null) || graphify=@GRAPHIFY@
|
|
15
|
+
[ -n "$graphify" ] && [ -x "$graphify" ] || exit 0
|
|
16
|
+
lock=$common/sidegraph-graph-refresh.lock
|
|
17
|
+
want=$common/sidegraph-graph-refresh.want
|
|
18
|
+
log=$common/sidegraph-graph-refresh.log
|
|
19
|
+
: > "$want" 2>/dev/null || exit 0
|
|
20
|
+
(
|
|
21
|
+
me=$(exec sh -c 'echo $PPID')
|
|
22
|
+
take() { mkdir "$lock" 2>/dev/null && echo "$me" > "$lock/pid"; }
|
|
23
|
+
if ! take; then
|
|
24
|
+
pid=$(cat "$lock/pid" 2>/dev/null)
|
|
25
|
+
if [ -n "$pid" ]; then
|
|
26
|
+
kill -0 "$pid" 2>/dev/null && exit 0 # a runner is alive; it will see $want
|
|
27
|
+
else # the owner is mid-write, or died there
|
|
28
|
+
[ -n "$(find "$lock" -maxdepth 0 -mmin +10 2>/dev/null)" ] || exit 0
|
|
29
|
+
fi
|
|
30
|
+
mkdir "$lock.gate" 2>/dev/null || exit 0 # one stale-breaker at a time
|
|
31
|
+
[ "$(cat "$lock/pid" 2>/dev/null)" = "$pid" ] &&
|
|
32
|
+
{ [ -n "$pid" ] || [ -n "$(find "$lock" -maxdepth 0 -mmin +10 2>/dev/null)" ]; } &&
|
|
33
|
+
rm -rf "$lock"
|
|
34
|
+
rmdir "$lock.gate"; take || exit 0
|
|
35
|
+
fi
|
|
36
|
+
cd "$top" || { rm -rf "$lock"; exit 0; }
|
|
37
|
+
while :; do
|
|
38
|
+
while [ -e "$want" ]; do
|
|
39
|
+
rm -f "$want"
|
|
40
|
+
GRAPHIFY_NO_AUTO_REFRESH=1 PYTHONHASHSEED=0 "$graphify" update . > "$log" 2>&1
|
|
41
|
+
done
|
|
42
|
+
rm -rf "$lock"; [ -e "$want" ] || break; take || break
|
|
43
|
+
done
|
|
44
|
+
) </dev/null >/dev/null 2>&1 &
|
|
45
|
+
exit 0
|
|
46
|
+
"""
|
|
@@ -255,27 +255,6 @@ def have_shell(name: str) -> bool:
|
|
|
255
255
|
return shutil.which(name) is not None
|
|
256
256
|
|
|
257
257
|
|
|
258
|
-
def _mkdir_is_uutils() -> bool:
|
|
259
|
-
"""True when ``mkdir`` on PATH is uutils coreutils, the default on Ubuntu 26.04."""
|
|
260
|
-
try:
|
|
261
|
-
out = subprocess.run(
|
|
262
|
-
["mkdir", "--version"], capture_output=True, text=True, timeout=5
|
|
263
|
-
).stdout
|
|
264
|
-
except (OSError, subprocess.SubprocessError):
|
|
265
|
-
return False
|
|
266
|
-
return "uutils" in out
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
# uutils ``mkdir`` 0.10 is not atomic under a race: two callers creating one directory can both
|
|
270
|
-
# exit 0, so the helper's mkdir lock lets two rebuilds run at once. The overlap tests are expected
|
|
271
|
-
# to fail there until the helper takes its lock without an external mkdir.
|
|
272
|
-
NON_ATOMIC_MKDIR = pytest.mark.xfail(
|
|
273
|
-
_mkdir_is_uutils(),
|
|
274
|
-
reason="uutils mkdir lets two racing callers both succeed; the helper lock relies on mkdir",
|
|
275
|
-
strict=False,
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
|
|
279
258
|
# -- helpers shared by test_githooks and the private lock-race tests ------------------------
|
|
280
259
|
|
|
281
260
|
SHELLS = [
|
|
@@ -20,7 +20,6 @@ from tests.githooks_support import (
|
|
|
20
20
|
CREATED_HEADER,
|
|
21
21
|
HELPER_NAME,
|
|
22
22
|
HOOKS,
|
|
23
|
-
NON_ATOMIC_MKDIR,
|
|
24
23
|
SHELLS,
|
|
25
24
|
STALE_STATES,
|
|
26
25
|
Sandbox,
|
|
@@ -462,13 +461,11 @@ def test_the_rebuild_is_graphify_update_with_a_pinned_hash_seed_and_a_log(sandbo
|
|
|
462
461
|
# tests/private/test_githooks.py; the two cases here keep the lock contract in every PR run.
|
|
463
462
|
|
|
464
463
|
|
|
465
|
-
@NON_ATOMIC_MKDIR
|
|
466
464
|
@pytest.mark.slow
|
|
467
465
|
def test_t9_two_simultaneous_calls_never_overlap_on_a_fresh_lock(sandbox, monkeypatch):
|
|
468
466
|
fresh_lock_burst(sandbox, monkeypatch, "sh", 2)
|
|
469
467
|
|
|
470
468
|
|
|
471
|
-
@NON_ATOMIC_MKDIR
|
|
472
469
|
@pytest.mark.slow
|
|
473
470
|
def test_t9_two_simultaneous_calls_never_overlap_on_a_dead_pid_lock(sandbox, monkeypatch):
|
|
474
471
|
stale_lock_burst(sandbox, monkeypatch, "sh", 2, "dead pid")
|
|
@@ -566,8 +563,8 @@ def test_a_pid_write_that_fails_does_not_block_later_rebuilds(sandbox):
|
|
|
566
563
|
)
|
|
567
564
|
assert done.returncode == 0
|
|
568
565
|
lock = info.common / f"{HELPER_NAME}.lock"
|
|
569
|
-
wait_for(
|
|
570
|
-
assert
|
|
566
|
+
wait_for(lock.is_file, what="the lock the failed write left")
|
|
567
|
+
assert lock.read_bytes() == b""
|
|
571
568
|
age(lock)
|
|
572
569
|
commit(repo)
|
|
573
570
|
starts = await_rebuilds(sandbox, info.common)
|