scar-cli 0.26.0__tar.gz → 0.27.0__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.
- scar_cli-0.27.0/.release-please-manifest.json +3 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/CHANGELOG.md +7 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/PKG-INFO +6 -1
- {scar_cli-0.26.0 → scar_cli-0.27.0}/README.md +5 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/plugin/plugin.json +1 -1
- {scar_cli-0.26.0 → scar_cli-0.27.0}/pyproject.toml +1 -1
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/cli.py +84 -6
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_docs.py +12 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_json_contract.py +2 -1
- scar_cli-0.27.0/tests/test_review_queue.py +173 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/uv.lock +1 -1
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/docs/agents.md +54 -0
- scar_cli-0.26.0/.release-please-manifest.json +0 -3
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.claude-plugin/marketplace.json +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.github/workflows/ci.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.github/workflows/docs.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.github/workflows/pr-validation.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.github/workflows/release.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.gitignore +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.pre-commit-config.yaml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.pre-commit-hooks.yaml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0001-git-grep-ere-pitfalls.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0002-agent-direct-hook-install.deadend.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0003-installer-binds-to-active-venv-scar.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0004-promote-roundtrip-drops-expires-evidence.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0005-history-rewrite-orphans-commit-evidence.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0006-yaml-pattern-anchor-over-escaping.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0007-release-please-config-change-skips-open-pr.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0008-rich-output-nontty-must-bypass-rich.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0009-anchor-survival-harness-measures-symbol-not-path-anchors.deadend.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0010-git-returncode-128-vs-empty-tracked-set.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0011-lint-compile-check-lets-redos-anchors-hang-hotpath.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0012-firing-log-readers-need-blanket-guards.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0013-docusaurus-future-v4-requires-faster-dep.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0014-inject-flag-dest-collides-with-subcommand-dispatch.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0015-zero-checkruns-means-approval-gate-not-workflow-bug.deadend.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0016-hook-ownership-must-be-kind-scoped.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0017-codex-pretool-context-can-replay-apply-patch.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0018-cli-subparsers-register-through-_add-wrapper.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0019-token-in-scar-body-cannot-prove-hook-delivery.deadend.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0020-one-directional-health-check-leaves-flattering-direction-unwatched.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0021-posttool-fix-in-hooks-does-not-reach-codex-or-cascade.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0022-codex-hook-delivery-needs-user-file-and-trust.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0023-cascade-block-exit-collides-with-argparse.fence.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0024-host-detection-must-not-read-the-process-home.deadend.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0025-one-plugin-hook-manifest-two-hosts-two-root-variables.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0026-path-anchor-breadth-drives-the-review-due-threshold.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/README.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/candidates/violation-evidence-must-not-persist-raw-edits.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/template.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/AGENTS.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/CONTRIBUTING.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/IDEA.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/LICENSE +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/ROADMAP.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/SCAR-FORMAT.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/SPEC.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/STRESS-TEST.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/action.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/codecov.yml +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/anchor-survival/PROTOCOL.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/anchor-survival/RESULTS.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/anchor-survival/long_replay.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/anchor-survival/replay.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/anchor-survival/replay_shipped.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/anchor-survival/test_replay_shipped.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/auto-authorship/FINDINGS.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/auto-authorship/PROTOCOL.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/.gitignore +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/PROTOCOL.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/RESULTS.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/fixture/.scars/0001-vendor-retry-window.fence.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/fixture/.scars/0002-evicting-session-store.deadend.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/fixture/.scars/0003-export-column-order.landmine.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/fixture/README.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/fixture/payments/retry.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/fixture/reports/export.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/fixture/services/sessions.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/fence-honor/grade.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/harvest/PROTOCOL.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/experiments/harvest/harvest.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/hook/scar-hooks.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/plugin/hooks/run.sh +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/plugin/skills/scar-authoring/SKILL.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/plugin/skills/scar-authoring/assets/template.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/release-please-config.json +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/__init__.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/agent.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/cascade.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/codex.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/draftcheck.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/evidence.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/firing_log.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/gc.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/harvest.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/hooks.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/hosts.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/installer.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/lint.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/match.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/mcp.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/model.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/orphan.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/output.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/reanchor.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/renames.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/render.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/review.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/skills/scar-authoring/SKILL.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/skills/scar-authoring/assets/template.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/store.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/symbols.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/src/scar/violation_evidence.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/conftest.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_action_yml.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_anchor_kind.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_block_capability.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_cascade.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_cli.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_codex.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_context_size.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_draftcheck.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_evidence.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_firing_log.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_gc.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_git_hook.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_harvest.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_hooks.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_hosts.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_installer.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_lifecycle.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_lint.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_match.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_matched_by.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_mcp.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_model.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_orphan.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_output.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_plugin.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_precommit_hooks.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_reanchor.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_renames.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_render.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_review.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_skill.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_store.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_sweep.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_symbols.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_verdict_observability.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/tests/test_violation_evidence.py +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/.gitignore +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/docs/concepts.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/docs/index.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/docs/methodology.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/docs/quickstart.md +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/docusaurus.config.ts +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/package-lock.json +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/package.json +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/scripts/sync-changelog.mjs +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/sidebars.ts +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/src/css/custom.css +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/static/img/favicon.svg +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/static/img/social-card.png +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/static/llms.txt +0 -0
- {scar_cli-0.26.0 → scar_cli-0.27.0}/website/tsconfig.json +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.27.0](https://github.com/Daily-Nerd/Scar/compare/v0.26.0...v0.27.0) (2026-11-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **lint:** rolling review queue from scar lint (--review-queue) ([#357](https://github.com/Daily-Nerd/Scar/issues/357)) ([8136513](https://github.com/Daily-Nerd/Scar/commit/8136513ef1c7cbba2ac2d7e1b4f0b68baf6544c0))
|
|
9
|
+
|
|
3
10
|
## [0.26.0](https://github.com/Daily-Nerd/Scar/compare/v0.25.1...v0.26.0) (2026-11-06)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: scar-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.0
|
|
4
4
|
Summary: SCAR — version control for negative knowledge (deadends, fences, landmines)
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -126,6 +126,11 @@ CI without pre-commit:
|
|
|
126
126
|
`@main` always tracks the latest commit; releases are tagged `vX.Y.Z` via
|
|
127
127
|
release-please, so pin a tag for reproducible CI.
|
|
128
128
|
|
|
129
|
+
`scar lint --review-queue` prints a markdown checklist of scars that need a human
|
|
130
|
+
(orphans, partial rot, symbol drift, unreachable evidence, passed `review_after`),
|
|
131
|
+
empty when there are none. The docs have a scheduled-workflow recipe that keeps
|
|
132
|
+
one rolling issue in sync with it: see [CI](https://daily-nerd.github.io/Scar/docs/agents#review-queue).
|
|
133
|
+
|
|
129
134
|
## Quality discipline
|
|
130
135
|
|
|
131
136
|
- **Candidates vs active:** agents and `scar harvest` only ever write to `.scars/candidates/`. A human promotes (`scar promote`) — nothing enters active enforcement without review.
|
|
@@ -111,6 +111,11 @@ CI without pre-commit:
|
|
|
111
111
|
`@main` always tracks the latest commit; releases are tagged `vX.Y.Z` via
|
|
112
112
|
release-please, so pin a tag for reproducible CI.
|
|
113
113
|
|
|
114
|
+
`scar lint --review-queue` prints a markdown checklist of scars that need a human
|
|
115
|
+
(orphans, partial rot, symbol drift, unreachable evidence, passed `review_after`),
|
|
116
|
+
empty when there are none. The docs have a scheduled-workflow recipe that keeps
|
|
117
|
+
one rolling issue in sync with it: see [CI](https://daily-nerd.github.io/Scar/docs/agents#review-queue).
|
|
118
|
+
|
|
114
119
|
## Quality discipline
|
|
115
120
|
|
|
116
121
|
- **Candidates vs active:** agents and `scar harvest` only ever write to `.scars/candidates/`. A human promotes (`scar promote`) — nothing enters active enforcement without review.
|
|
@@ -546,6 +546,74 @@ def _firing_reviews(store):
|
|
|
546
546
|
return []
|
|
547
547
|
|
|
548
548
|
|
|
549
|
+
def _review_due(store) -> list[Scar]:
|
|
550
|
+
"""Firing scars whose review_after date has passed. The one definition
|
|
551
|
+
shared by `status` and `lint` so the two JSON surfaces cannot disagree."""
|
|
552
|
+
today = time.strftime("%Y-%m-%d")
|
|
553
|
+
return [s for _f, s in store.firing() if s.review_after and s.review_after < today]
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def _review_due_json(due: list[Scar]) -> list[dict]:
|
|
557
|
+
return [{"type": s.type, "id": s.id, "review_after": s.review_after} for s in due]
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
def _review_queue_markdown(store, data: dict) -> str:
|
|
561
|
+
"""Markdown checklist of scars a human should look at, built from the SAME
|
|
562
|
+
dict `lint --json` emits (#354). One row per scar, states merged. Only
|
|
563
|
+
CI-usable signals: the firing log is machine-local and empty on a fresh
|
|
564
|
+
checkout, so firing_review and never_fired are deliberately absent.
|
|
565
|
+
|
|
566
|
+
Only the id, title, a path and fixed state wording are printed. The
|
|
567
|
+
`reason` strings in `data` embed anchor text and violation hints, so they
|
|
568
|
+
are never used here, and the body and evidence are never read."""
|
|
569
|
+
by_id: dict[int, tuple[Path, Scar]] = {}
|
|
570
|
+
for f, s in store.parsed():
|
|
571
|
+
if s.id is not None:
|
|
572
|
+
by_id.setdefault(s.id, (f, s))
|
|
573
|
+
|
|
574
|
+
states: dict[int, list[str]] = {}
|
|
575
|
+
cmds: dict[int, list[str]] = {}
|
|
576
|
+
|
|
577
|
+
def add(scar_id: int, state: str, cmd: str) -> None:
|
|
578
|
+
if state not in states.setdefault(scar_id, []):
|
|
579
|
+
states[scar_id].append(state)
|
|
580
|
+
if cmd not in cmds.setdefault(scar_id, []):
|
|
581
|
+
cmds[scar_id].append(cmd)
|
|
582
|
+
|
|
583
|
+
for o in data["orphans"]:
|
|
584
|
+
add(o["scar_id"], "orphan (all anchors dead)", "`scar reanchor`")
|
|
585
|
+
for pr in data["partial_rot"]:
|
|
586
|
+
add(pr["scar_id"], "partial rot (dead anchor among live ones)", "`scar reanchor`")
|
|
587
|
+
for d in data["symbol_drift"]:
|
|
588
|
+
add(d["scar_id"], "symbol drift", "`scar why <path>`")
|
|
589
|
+
for ue in data["unreachable_evidence"]:
|
|
590
|
+
add(ue["scar_id"], "evidence commit unreachable", "`scar why <path>`")
|
|
591
|
+
for r in data["revivals"]:
|
|
592
|
+
add(r["scar_id"], "archived but revives_if matches again", "`scar why <path>`")
|
|
593
|
+
for rd in data["review_due"]:
|
|
594
|
+
add(rd["id"], f"review_after {rd['review_after']} passed",
|
|
595
|
+
f"`scar archive {rd['id']} --reason \"...\"` or bump review_after")
|
|
596
|
+
|
|
597
|
+
if not states:
|
|
598
|
+
return ""
|
|
599
|
+
lines = []
|
|
600
|
+
for scar_id in sorted(states):
|
|
601
|
+
found = by_id.get(scar_id)
|
|
602
|
+
if found:
|
|
603
|
+
f, s = found
|
|
604
|
+
where = s.path_anchors[0] if s.path_anchors else f.name
|
|
605
|
+
title = s.title
|
|
606
|
+
else:
|
|
607
|
+
where, title = "unknown file", "(scar not found)"
|
|
608
|
+
cmd = "; ".join(cmds[scar_id]).replace("<path>", where)
|
|
609
|
+
lines.append(f"- [ ] #{scar_id} {title} ({where}): "
|
|
610
|
+
f"{'; '.join(states[scar_id])}. Suggested: {cmd}")
|
|
611
|
+
lines.append("")
|
|
612
|
+
lines.append("Firing-log signals (firing review, never fired) are not included: "
|
|
613
|
+
"the firing log is machine-local and empty in CI.")
|
|
614
|
+
return "\n".join(lines) + "\n"
|
|
615
|
+
|
|
616
|
+
|
|
549
617
|
def _cmd_lint(args) -> int:
|
|
550
618
|
store = _require_store()
|
|
551
619
|
if store is None:
|
|
@@ -733,6 +801,7 @@ def _cmd_lint(args) -> int:
|
|
|
733
801
|
# revised. Advisory like every other lifecycle signal here — only the
|
|
734
802
|
# opt-in --fail-firing-review turns it into an exit code.
|
|
735
803
|
reviews = _firing_reviews(store)
|
|
804
|
+
review_due = _review_due(store)
|
|
736
805
|
|
|
737
806
|
# evidence reachability (#43, scar #5): commit-SHA receipts that no longer
|
|
738
807
|
# resolve from HEAD. None = shallow clone, reachability indeterminate → skip.
|
|
@@ -762,6 +831,7 @@ def _cmd_lint(args) -> int:
|
|
|
762
831
|
"unreachable_evidence": [{"scar_id": ue.scar_id, "sha": ue.sha, "reason": ue.reason}
|
|
763
832
|
for ue in unreachable],
|
|
764
833
|
"failed": failed,
|
|
834
|
+
"review_due": _review_due_json(review_due),
|
|
765
835
|
}
|
|
766
836
|
|
|
767
837
|
def plain():
|
|
@@ -809,8 +879,13 @@ def _cmd_lint(args) -> int:
|
|
|
809
879
|
f"{len(unreachable)} unreachable-evidence, "
|
|
810
880
|
f"{len(reviews)} firing-review")
|
|
811
881
|
|
|
812
|
-
|
|
813
|
-
|
|
882
|
+
if getattr(args, "review_queue", False):
|
|
883
|
+
# Machine path: plain markdown, never rich, and empty stdout when the
|
|
884
|
+
# queue is empty so a workflow can close its issue on `-s queue.md`.
|
|
885
|
+
sys.stdout.write(_review_queue_markdown(store, data))
|
|
886
|
+
else:
|
|
887
|
+
output.render(data=data, json_flag=getattr(args, "json", False),
|
|
888
|
+
tty=lambda: _lint_rich(data), plain=plain)
|
|
814
889
|
|
|
815
890
|
if failed:
|
|
816
891
|
return 1
|
|
@@ -829,8 +904,7 @@ def _cmd_status(args) -> int:
|
|
|
829
904
|
return 1
|
|
830
905
|
active, broken, cands = store.active(), store.broken(), store.candidates()
|
|
831
906
|
challenged = [(f, s) for f, s in store.parsed() if s.status == "challenged"]
|
|
832
|
-
|
|
833
|
-
due = [s for _, s in store.firing() if s.review_after and s.review_after < today]
|
|
907
|
+
due = _review_due(store)
|
|
834
908
|
|
|
835
909
|
# Orphans: detected (firing scars whose anchors all died — not yet persisted)
|
|
836
910
|
# and persisted (already flipped to status: orphaned, invisible until now).
|
|
@@ -849,7 +923,7 @@ def _cmd_status(args) -> int:
|
|
|
849
923
|
for _f, s in active],
|
|
850
924
|
"challenged": [{"type": s.type, "id": s.id, "title": s.title} for _f, s in challenged],
|
|
851
925
|
"candidates": [c.name for c in cands],
|
|
852
|
-
"review_due":
|
|
926
|
+
"review_due": _review_due_json(due),
|
|
853
927
|
# Count-based review trigger (#274), kept SEPARATE from review_due:
|
|
854
928
|
# one is a date passing, the other is accumulated firings, and a
|
|
855
929
|
# consumer that merges them cannot tell which obligation it is looking
|
|
@@ -3116,7 +3190,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
3116
3190
|
p.add_argument("--fail-firing-review", action="store_true",
|
|
3117
3191
|
help="exit non-zero when any scar has crossed its "
|
|
3118
3192
|
"review_after_firings threshold")
|
|
3119
|
-
p.
|
|
3193
|
+
fmt = p.add_mutually_exclusive_group()
|
|
3194
|
+
fmt.add_argument("--json", action="store_true", help="emit machine-readable JSON")
|
|
3195
|
+
fmt.add_argument("--review-queue", action="store_true",
|
|
3196
|
+
help="print a markdown checklist of scars needing a human "
|
|
3197
|
+
"(CI-usable signals only); empty output when none")
|
|
3120
3198
|
p = _add(sub, "status", _cmd_status, help="counts, titles, broken-file warnings")
|
|
3121
3199
|
p.add_argument("--json", action="store_true", help="emit machine-readable JSON")
|
|
3122
3200
|
|
|
@@ -36,3 +36,15 @@ def test_agents_doc_documents_native_codex_hooks_and_trust():
|
|
|
36
36
|
assert "Bash" in text and "apply_patch" in text
|
|
37
37
|
assert "/hooks" in text
|
|
38
38
|
assert "silently" in text
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_agents_doc_documents_review_queue_recipe():
|
|
42
|
+
"""#354: the rolling review issue is a documented recipe over
|
|
43
|
+
`scar lint --review-queue`, not a subcommand."""
|
|
44
|
+
text = (ROOT / "website" / "docs" / "agents.md").read_text(encoding="utf-8")
|
|
45
|
+
assert "### Review queue" in text
|
|
46
|
+
assert "scar lint --review-queue" in text
|
|
47
|
+
assert "scar-review-queue" in text
|
|
48
|
+
assert "issues: write" in text
|
|
49
|
+
assert "fetch-depth: 0" in text
|
|
50
|
+
assert "\u2014" not in text.split("### Review queue")[1].split("## Machine-readable")[0]
|
|
@@ -36,7 +36,8 @@ ROOT = Path(__file__).resolve().parent.parent
|
|
|
36
36
|
GUARANTEED: dict[str, set[str]] = {
|
|
37
37
|
"lint": {"files", "findings", "failed", "orphans", "partial_rot",
|
|
38
38
|
"symbol_drift", "revivals", "reverse_hints",
|
|
39
|
-
"unreachable_evidence", "shallow_clone", "symbols_unchecked"
|
|
39
|
+
"unreachable_evidence", "shallow_clone", "symbols_unchecked",
|
|
40
|
+
"review_due"},
|
|
40
41
|
"status": {"scars_dir", "active", "challenged", "candidates", "review_due",
|
|
41
42
|
"orphan_detected", "orphaned", "partial_rot", "broken", "counts"},
|
|
42
43
|
"check": {"paths", "scars"},
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Review queue (#354): lint --json carries review_due, and
|
|
2
|
+
`lint --review-queue` renders the CI-usable review signals as markdown."""
|
|
3
|
+
import json
|
|
4
|
+
import subprocess
|
|
5
|
+
|
|
6
|
+
from scar.cli import main
|
|
7
|
+
from scar.store import init_scars
|
|
8
|
+
|
|
9
|
+
SCAR = """\
|
|
10
|
+
---
|
|
11
|
+
id: {id}
|
|
12
|
+
type: landmine
|
|
13
|
+
title: {title}
|
|
14
|
+
severity: medium
|
|
15
|
+
confidence: 0.8
|
|
16
|
+
created: 2026-06-10
|
|
17
|
+
authors: ["claude-code"]
|
|
18
|
+
anchors:
|
|
19
|
+
{anchors}
|
|
20
|
+
evidence:
|
|
21
|
+
- commit: abc1234
|
|
22
|
+
{extra}status: active
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
{body}
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _write(root, name, *, id, title, anchors, extra="", body="Plain body."):
|
|
30
|
+
text = SCAR.format(id=id, title=title, anchors="\n".join(
|
|
31
|
+
f" - path: {a}" for a in anchors), extra=extra, body=body)
|
|
32
|
+
(root / ".scars" / name).write_text(text)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _repo(tmp_path, monkeypatch):
|
|
36
|
+
subprocess.run(["git", "init", "-q"], cwd=tmp_path, check=True)
|
|
37
|
+
subprocess.run(["git", "config", "user.email", "t@t.t"], cwd=tmp_path, check=True)
|
|
38
|
+
subprocess.run(["git", "config", "user.name", "t"], cwd=tmp_path, check=True)
|
|
39
|
+
init_scars(tmp_path)
|
|
40
|
+
(tmp_path / "src" / "live").mkdir(parents=True)
|
|
41
|
+
(tmp_path / "src" / "live" / "mod.py").write_text("x = 1\n")
|
|
42
|
+
monkeypatch.chdir(tmp_path)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _commit(root):
|
|
46
|
+
"""Commit, then point every scar's evidence at that real commit so the
|
|
47
|
+
fixtures are not accidentally flagged as unreachable-evidence."""
|
|
48
|
+
subprocess.run(["git", "add", "-A"], cwd=root, check=True)
|
|
49
|
+
subprocess.run(["git", "commit", "-q", "-m", "init"], cwd=root, check=True)
|
|
50
|
+
sha = subprocess.run(["git", "rev-parse", "HEAD"], cwd=root, check=True,
|
|
51
|
+
capture_output=True, text=True).stdout.strip()
|
|
52
|
+
for f in (root / ".scars").glob("0*.md"):
|
|
53
|
+
f.write_text(f.read_text().replace("abc1234", sha))
|
|
54
|
+
subprocess.run(["git", "add", "-A"], cwd=root, check=True)
|
|
55
|
+
subprocess.run(["git", "commit", "-q", "-m", "evidence"], cwd=root, check=True)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _due_and_rot(tmp_path, monkeypatch):
|
|
59
|
+
_repo(tmp_path, monkeypatch)
|
|
60
|
+
_write(tmp_path, "0001-due.landmine.md", id=1, title="Due scar",
|
|
61
|
+
anchors=["src/live/"], extra="review_after: 2020-01-01\n")
|
|
62
|
+
_write(tmp_path, "0002-rot.landmine.md", id=2, title="Rotted scar",
|
|
63
|
+
anchors=["src/live/", "src/gone/"], body="SECRET-BODY-TEXT")
|
|
64
|
+
_commit(tmp_path)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_lint_json_review_due_matches_status(tmp_path, monkeypatch, capsys):
|
|
68
|
+
_due_and_rot(tmp_path, monkeypatch)
|
|
69
|
+
main(["lint", "--json"])
|
|
70
|
+
lint_due = json.loads(capsys.readouterr().out)["review_due"]
|
|
71
|
+
main(["status", "--json"])
|
|
72
|
+
status_due = json.loads(capsys.readouterr().out)["review_due"]
|
|
73
|
+
assert lint_due == status_due
|
|
74
|
+
assert [d["id"] for d in lint_due] == [1]
|
|
75
|
+
assert lint_due[0]["review_after"] == "2020-01-01"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_lint_json_review_due_empty_list_when_none(tmp_path, monkeypatch, capsys):
|
|
79
|
+
_repo(tmp_path, monkeypatch)
|
|
80
|
+
main(["lint", "--json"])
|
|
81
|
+
assert json.loads(capsys.readouterr().out)["review_due"] == []
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# --- lint --review-queue ---
|
|
85
|
+
|
|
86
|
+
def _queue(capsys, *extra):
|
|
87
|
+
rc = main(["lint", "--review-queue", *extra])
|
|
88
|
+
return rc, capsys.readouterr().out
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_review_queue_empty_store_prints_nothing(tmp_path, monkeypatch, capsys):
|
|
92
|
+
_repo(tmp_path, monkeypatch)
|
|
93
|
+
rc, out = _queue(capsys)
|
|
94
|
+
assert rc == 0
|
|
95
|
+
assert out == ""
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_review_queue_one_row_per_flagged_scar(tmp_path, monkeypatch, capsys):
|
|
99
|
+
_due_and_rot(tmp_path, monkeypatch)
|
|
100
|
+
rc, out = _queue(capsys)
|
|
101
|
+
assert rc == 0
|
|
102
|
+
rows = [ln for ln in out.splitlines() if ln.startswith("- [ ] ")]
|
|
103
|
+
assert len(rows) == 2
|
|
104
|
+
due = next(r for r in rows if "#1 " in r)
|
|
105
|
+
rot = next(r for r in rows if "#2 " in r)
|
|
106
|
+
assert "Due scar" in due and "src/live/" in due
|
|
107
|
+
assert "review_after 2020-01-01" in due
|
|
108
|
+
assert "Suggested:" in due and "scar archive 1" in due
|
|
109
|
+
assert "Rotted scar" in rot and "partial rot" in rot
|
|
110
|
+
assert "Suggested: `scar reanchor`" in rot
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_review_queue_merges_states_into_one_row(tmp_path, monkeypatch, capsys):
|
|
114
|
+
_repo(tmp_path, monkeypatch)
|
|
115
|
+
_write(tmp_path, "0003-both.landmine.md", id=3, title="Both",
|
|
116
|
+
anchors=["src/live/", "src/gone/"], extra="review_after: 2020-01-01\n")
|
|
117
|
+
_commit(tmp_path)
|
|
118
|
+
_, out = _queue(capsys)
|
|
119
|
+
rows = [ln for ln in out.splitlines() if "#3 " in ln]
|
|
120
|
+
assert len(rows) == 1
|
|
121
|
+
assert "partial rot" in rows[0] and "review_after 2020-01-01" in rows[0]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def test_review_queue_never_prints_body_or_violation(tmp_path, monkeypatch, capsys):
|
|
125
|
+
_repo(tmp_path, monkeypatch)
|
|
126
|
+
_write(tmp_path, "0004-v.landmine.md", id=4, title="Violating",
|
|
127
|
+
anchors=["src/live/", "src/gone/"],
|
|
128
|
+
extra="violation: 'LEAKY_REGEX_\\d+'\n",
|
|
129
|
+
body="SECRET-BODY-TEXT")
|
|
130
|
+
_commit(tmp_path)
|
|
131
|
+
_, out = _queue(capsys)
|
|
132
|
+
assert "#4" in out
|
|
133
|
+
assert "SECRET-BODY-TEXT" not in out
|
|
134
|
+
assert "LEAKY_REGEX" not in out
|
|
135
|
+
assert "evidence" not in out.lower()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_review_queue_excludes_firing_log_signals(tmp_path, monkeypatch, capsys):
|
|
139
|
+
_repo(tmp_path, monkeypatch)
|
|
140
|
+
_write(tmp_path, "0005-n.landmine.md", id=5, title="Healthy",
|
|
141
|
+
anchors=["src/live/"], extra="review_after_firings: 1\n")
|
|
142
|
+
_commit(tmp_path)
|
|
143
|
+
_, out = _queue(capsys)
|
|
144
|
+
assert out == ""
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_review_queue_notes_firing_log_exclusion_when_non_empty(tmp_path, monkeypatch, capsys):
|
|
148
|
+
_due_and_rot(tmp_path, monkeypatch)
|
|
149
|
+
_, out = _queue(capsys)
|
|
150
|
+
last = out.rstrip("\n").splitlines()[-1]
|
|
151
|
+
assert "firing" in last.lower()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_review_queue_plain_even_on_tty(tmp_path, monkeypatch, capsys):
|
|
155
|
+
from scar import output
|
|
156
|
+
_due_and_rot(tmp_path, monkeypatch)
|
|
157
|
+
monkeypatch.setattr(output, "is_tty", lambda: True)
|
|
158
|
+
_, out = _queue(capsys)
|
|
159
|
+
assert "\x1b[" not in out
|
|
160
|
+
assert "- [ ] #1 " in out
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_review_queue_does_not_change_exit_codes(tmp_path, monkeypatch, capsys):
|
|
164
|
+
_due_and_rot(tmp_path, monkeypatch)
|
|
165
|
+
rc, _ = _queue(capsys, "--fail-partial-rot")
|
|
166
|
+
assert rc == 1
|
|
167
|
+
assert main(["lint", "--fail-partial-rot"]) == 1
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def test_review_queue_has_no_em_dash(tmp_path, monkeypatch, capsys):
|
|
171
|
+
_due_and_rot(tmp_path, monkeypatch)
|
|
172
|
+
_, out = _queue(capsys)
|
|
173
|
+
assert "\u2014" not in out
|
|
@@ -183,6 +183,60 @@ scar lint # format, dead tripwires, overdue
|
|
|
183
183
|
|
|
184
184
|
Advisory by default everywhere; CI opts into strictness explicitly.
|
|
185
185
|
|
|
186
|
+
### Review queue
|
|
187
|
+
|
|
188
|
+
Orphans, partial rot, symbol drift, unreachable evidence, revivals and passed `review_after` dates all end in a red job or a terminal warning that nobody owns. `scar lint --review-queue` turns them into one markdown checklist, one row per scar, and a scheduled workflow keeps a single rolling issue in sync with it:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
scar lint --review-queue
|
|
192
|
+
# - [ ] #7 One anchor alive, one rotted (src/live/): partial rot (dead anchor among live ones). Suggested: `scar reanchor`
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The output is plain text with no scar bodies, evidence or violation patterns: only id, title, path, state and a suggested command. When nothing needs review it prints nothing and exits 0. Exit codes follow the usual gates (`--fail-orphans` and friends), the flag only changes what is printed. The firing-log signals (firing review, never fired) are left out on purpose: that log lives on each developer's machine and is empty on a CI checkout.
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
# .github/workflows/scar-review-queue.yml
|
|
199
|
+
name: Scar review queue
|
|
200
|
+
on:
|
|
201
|
+
schedule:
|
|
202
|
+
- cron: '0 7 * * 1'
|
|
203
|
+
workflow_dispatch:
|
|
204
|
+
|
|
205
|
+
permissions:
|
|
206
|
+
contents: read
|
|
207
|
+
issues: write
|
|
208
|
+
|
|
209
|
+
jobs:
|
|
210
|
+
queue:
|
|
211
|
+
runs-on: ubuntu-latest
|
|
212
|
+
steps:
|
|
213
|
+
- uses: actions/checkout@v4
|
|
214
|
+
with:
|
|
215
|
+
fetch-depth: 0 # evidence-reachability checks need full history
|
|
216
|
+
- uses: astral-sh/setup-uv@v5
|
|
217
|
+
- name: Build the queue
|
|
218
|
+
run: uvx --from scar-cli scar lint --review-queue > queue.md
|
|
219
|
+
- name: Sync the rolling issue
|
|
220
|
+
env:
|
|
221
|
+
GH_TOKEN: ${{ github.token }}
|
|
222
|
+
run: |
|
|
223
|
+
label=scar-review-queue
|
|
224
|
+
gh label create "$label" --color BFD4F2 --description "Rolling Scar review queue" 2>/dev/null || true
|
|
225
|
+
number=$(gh issue list --label "$label" --state all --limit 1 --json number --jq '.[0].number // empty')
|
|
226
|
+
if [ -s queue.md ]; then
|
|
227
|
+
if [ -z "$number" ]; then
|
|
228
|
+
gh issue create --title "Scar review queue" --label "$label" --body-file queue.md
|
|
229
|
+
else
|
|
230
|
+
gh issue edit "$number" --body-file queue.md
|
|
231
|
+
gh issue reopen "$number" 2>/dev/null || true
|
|
232
|
+
fi
|
|
233
|
+
elif [ -n "$number" ]; then
|
|
234
|
+
gh issue close "$number" --comment "Review queue is empty." 2>/dev/null || true
|
|
235
|
+
fi
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The issue is rewritten from scar's output on every run, never duplicated, closed when the queue is empty and reopened when it is not. Its visibility follows the repository's: on a public repo the titles and file paths in the checklist are public too.
|
|
239
|
+
|
|
186
240
|
## Machine-readable docs
|
|
187
241
|
|
|
188
242
|
Agents reading these docs programmatically: fetch [`/llms.txt`](pathname:///Scar/llms.txt) for a plain-text index of every page with stable URLs, plus the changelog.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0003-installer-binds-to-active-venv-scar.landmine.md
RENAMED
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0004-promote-roundtrip-drops-expires-evidence.landmine.md
RENAMED
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0005-history-rewrite-orphans-commit-evidence.landmine.md
RENAMED
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0006-yaml-pattern-anchor-over-escaping.landmine.md
RENAMED
|
File without changes
|
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0008-rich-output-nontty-must-bypass-rich.landmine.md
RENAMED
|
File without changes
|
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0010-git-returncode-128-vs-empty-tracked-set.landmine.md
RENAMED
|
File without changes
|
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0012-firing-log-readers-need-blanket-guards.landmine.md
RENAMED
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0013-docusaurus-future-v4-requires-faster-dep.landmine.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0016-hook-ownership-must-be-kind-scoped.landmine.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scar_cli-0.26.0 → scar_cli-0.27.0}/.scars/0023-cascade-block-exit-collides-with-argparse.fence.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|