scar-cli 0.20.0__tar.gz → 0.22.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.22.0/.github/ISSUE_TEMPLATE/bug_report.yml +112 -0
- scar_cli-0.22.0/.github/ISSUE_TEMPLATE/config.yml +18 -0
- scar_cli-0.22.0/.github/ISSUE_TEMPLATE/feature_request.yml +70 -0
- scar_cli-0.22.0/.github/PULL_REQUEST_TEMPLATE.md +70 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.github/workflows/ci.yml +33 -2
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.gitignore +5 -0
- scar_cli-0.22.0/.release-please-manifest.json +3 -0
- scar_cli-0.22.0/.scars/0018-cli-subparsers-register-through-_add-wrapper.landmine.md +35 -0
- scar_cli-0.20.0/.scars/candidates/token-in-scar-body-cannot-prove-hook-delivery.md → scar_cli-0.22.0/.scars/0019-token-in-scar-body-cannot-prove-hook-delivery.deadend.md +3 -8
- scar_cli-0.22.0/.scars/candidates/one-directional-health-check-leaves-flattering-direction-unwatched.md +42 -0
- scar_cli-0.22.0/.scars/candidates/posttool-fix-in-hooks-does-not-reach-codex-or-cascade.md +36 -0
- {scar_cli-0.20.0/src/scar/skills/scar-authoring/assets → scar_cli-0.22.0/.scars}/template.md +1 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/CHANGELOG.md +47 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/PKG-INFO +1 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/SCAR-FORMAT.md +5 -2
- scar_cli-0.22.0/SPEC.md +466 -0
- scar_cli-0.22.0/codecov.yml +71 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/plugin/plugin.json +1 -1
- {scar_cli-0.20.0/.scars → scar_cli-0.22.0/plugin/skills/scar-authoring/assets}/template.md +1 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/pyproject.toml +2 -2
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/cascade.py +32 -13
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/cli.py +501 -16
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/codex.py +53 -18
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/hooks.py +200 -27
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/installer.py +63 -2
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/lint.py +17 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/match.py +146 -23
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/model.py +46 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/orphan.py +8 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/reanchor.py +15 -0
- scar_cli-0.22.0/src/scar/review.py +173 -0
- {scar_cli-0.20.0/plugin → scar_cli-0.22.0/src/scar}/skills/scar-authoring/assets/template.md +1 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/store.py +30 -7
- scar_cli-0.22.0/tests/test_anchor_kind.py +275 -0
- scar_cli-0.22.0/tests/test_block_capability.py +175 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_cascade.py +67 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_cli.py +519 -7
- scar_cli-0.22.0/tests/test_codex.py +447 -0
- scar_cli-0.22.0/tests/test_context_size.py +159 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_hooks.py +185 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_installer.py +96 -0
- scar_cli-0.22.0/tests/test_json_contract.py +273 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_lint.py +26 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_match.py +80 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_model.py +53 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_orphan.py +52 -7
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_reanchor.py +26 -0
- scar_cli-0.22.0/tests/test_review.py +362 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_store.py +138 -6
- scar_cli-0.22.0/tests/test_verdict_observability.py +368 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/uv.lock +150 -1
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/docs/methodology.md +24 -1
- scar_cli-0.20.0/.release-please-manifest.json +0 -3
- scar_cli-0.20.0/SPEC.md +0 -164
- scar_cli-0.20.0/tests/test_codex.py +0 -253
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.claude-plugin/marketplace.json +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.github/workflows/docs.yml +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.github/workflows/pr-validation.yml +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.github/workflows/release.yml +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.pre-commit-config.yaml +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.pre-commit-hooks.yaml +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0001-git-grep-ere-pitfalls.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0002-agent-direct-hook-install.deadend.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0003-installer-binds-to-active-venv-scar.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0004-promote-roundtrip-drops-expires-evidence.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0005-history-rewrite-orphans-commit-evidence.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0006-yaml-pattern-anchor-over-escaping.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0007-release-please-config-change-skips-open-pr.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0008-rich-output-nontty-must-bypass-rich.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0009-anchor-survival-harness-measures-symbol-not-path-anchors.deadend.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0010-git-returncode-128-vs-empty-tracked-set.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0011-lint-compile-check-lets-redos-anchors-hang-hotpath.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0012-firing-log-readers-need-blanket-guards.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0013-docusaurus-future-v4-requires-faster-dep.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0014-inject-flag-dest-collides-with-subcommand-dispatch.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0015-zero-checkruns-means-approval-gate-not-workflow-bug.deadend.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0016-hook-ownership-must-be-kind-scoped.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/0017-codex-pretool-context-can-replay-apply-patch.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/README.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/candidates/cascade-block-exit-collides-with-argparse.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/.scars/candidates/codex-hook-delivery-needs-user-file-and-trust.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/AGENTS.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/CONTRIBUTING.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/IDEA.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/LICENSE +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/README.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/ROADMAP.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/STRESS-TEST.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/action.yml +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/anchor-survival/PROTOCOL.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/anchor-survival/RESULTS.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/anchor-survival/long_replay.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/anchor-survival/replay.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/anchor-survival/replay_shipped.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/anchor-survival/test_replay_shipped.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/auto-authorship/FINDINGS.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/auto-authorship/PROTOCOL.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/.gitignore +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/PROTOCOL.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/RESULTS.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/fixture/.scars/0001-vendor-retry-window.fence.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/fixture/.scars/0002-evicting-session-store.deadend.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/fixture/.scars/0003-export-column-order.landmine.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/fixture/README.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/fixture/payments/retry.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/fixture/reports/export.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/fixture/services/sessions.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/fence-honor/grade.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/harvest/PROTOCOL.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/experiments/harvest/harvest.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/hook/scar-hooks.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/plugin/hooks/hooks.json +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/plugin/hooks/run.sh +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/plugin/skills/scar-authoring/SKILL.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/release-please-config.json +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/__init__.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/agent.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/draftcheck.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/evidence.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/gc.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/harvest.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/mcp.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/output.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/renames.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/render.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/skills/scar-authoring/SKILL.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/src/scar/symbols.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/conftest.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_action_yml.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_docs.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_draftcheck.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_evidence.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_gc.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_git_hook.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_harvest.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_lifecycle.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_mcp.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_output.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_plugin.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_precommit_hooks.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_renames.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_render.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_skill.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/tests/test_symbols.py +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/.gitignore +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/docs/agents.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/docs/concepts.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/docs/index.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/docs/quickstart.md +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/docusaurus.config.ts +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/package-lock.json +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/package.json +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/scripts/sync-changelog.mjs +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/sidebars.ts +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/src/css/custom.css +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/static/img/favicon.svg +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/static/llms.txt +0 -0
- {scar_cli-0.20.0 → scar_cli-0.22.0}/website/tsconfig.json +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something broke — anchoring, hooks, injection, CLI, lint, or stats
|
|
3
|
+
title: "fix: "
|
|
4
|
+
labels: ["bug", "type:fix"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Scar is entirely local — no service, no accounts, no telemetry. That means
|
|
10
|
+
nothing about your setup reaches us unless you paste it, and the diagnostics
|
|
11
|
+
below answer most questions in one round-trip.
|
|
12
|
+
|
|
13
|
+
**A maintainer must add `status:approved` to this issue before a PR can be
|
|
14
|
+
opened against it.** CI enforces that, so please wait for the label rather
|
|
15
|
+
than opening a PR alongside the report.
|
|
16
|
+
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: what-happened
|
|
19
|
+
attributes:
|
|
20
|
+
label: What happened
|
|
21
|
+
description: What you did and what broke. Quote error text exactly.
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
24
|
+
|
|
25
|
+
- type: textarea
|
|
26
|
+
id: expected
|
|
27
|
+
attributes:
|
|
28
|
+
label: What you expected
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
- type: textarea
|
|
33
|
+
id: repro
|
|
34
|
+
attributes:
|
|
35
|
+
label: Steps to reproduce
|
|
36
|
+
placeholder: |
|
|
37
|
+
1. scar init
|
|
38
|
+
2. scar hook install
|
|
39
|
+
3. edit a file matching an anchor
|
|
40
|
+
4. ...
|
|
41
|
+
validations:
|
|
42
|
+
required: false
|
|
43
|
+
|
|
44
|
+
- type: dropdown
|
|
45
|
+
id: runtime
|
|
46
|
+
attributes:
|
|
47
|
+
label: Agent runtime
|
|
48
|
+
description: Where Scar was running when this happened.
|
|
49
|
+
options:
|
|
50
|
+
- Claude Code
|
|
51
|
+
- Codex
|
|
52
|
+
- Cursor
|
|
53
|
+
- opencode
|
|
54
|
+
- Windsurf / Cascade
|
|
55
|
+
- An MCP client (scar mcp)
|
|
56
|
+
- No agent — scar CLI directly
|
|
57
|
+
- Other (say which in "What happened")
|
|
58
|
+
validations:
|
|
59
|
+
required: true
|
|
60
|
+
|
|
61
|
+
- type: dropdown
|
|
62
|
+
id: install
|
|
63
|
+
attributes:
|
|
64
|
+
label: How is scar installed?
|
|
65
|
+
description: Matters more than it looks — a local editable install never upgrades.
|
|
66
|
+
options:
|
|
67
|
+
- uv tool install
|
|
68
|
+
- pipx
|
|
69
|
+
- pip
|
|
70
|
+
- editable / from source
|
|
71
|
+
- don't know
|
|
72
|
+
validations:
|
|
73
|
+
required: false
|
|
74
|
+
|
|
75
|
+
- type: textarea
|
|
76
|
+
id: diagnostics
|
|
77
|
+
attributes:
|
|
78
|
+
label: Diagnostics
|
|
79
|
+
description: |
|
|
80
|
+
Paste the output of these. All local; nothing is transmitted by running them.
|
|
81
|
+
|
|
82
|
+
scar --version
|
|
83
|
+
scar status
|
|
84
|
+
scar hook status
|
|
85
|
+
scar lint
|
|
86
|
+
|
|
87
|
+
If the symbol/tree-sitter extra is involved, add whether you installed
|
|
88
|
+
`scar-cli[symbols]` — `--force` reinstalls have been known to drop extras.
|
|
89
|
+
render: text
|
|
90
|
+
validations:
|
|
91
|
+
required: true
|
|
92
|
+
|
|
93
|
+
- type: markdown
|
|
94
|
+
attributes:
|
|
95
|
+
value: |
|
|
96
|
+
### ⚠️ Before you paste anything else
|
|
97
|
+
|
|
98
|
+
**Do not paste `scar stats --all-repos` or the raw firing log.** Both are
|
|
99
|
+
machine-global: they name **every repository on your machine**, including
|
|
100
|
+
private ones. Plain `scar stats` is scoped to the current repo and is safe.
|
|
101
|
+
|
|
102
|
+
If a machine-global number is genuinely relevant, redact the repo names and
|
|
103
|
+
keep only the counts.
|
|
104
|
+
|
|
105
|
+
- type: textarea
|
|
106
|
+
id: stats
|
|
107
|
+
attributes:
|
|
108
|
+
label: "`scar stats` (optional)"
|
|
109
|
+
description: Current repo only. Useful for injection, retrieval or firing-log bugs.
|
|
110
|
+
render: text
|
|
111
|
+
validations:
|
|
112
|
+
required: false
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Blank issues are disabled: the two templates cover the cases that become
|
|
2
|
+
# work, and anything else is a question, which belongs in Discussions.
|
|
3
|
+
#
|
|
4
|
+
# This is only safe BECAUSE Discussions is enabled (turned on 2026-08-29). If
|
|
5
|
+
# Discussions is ever turned off again, flip this back to true — otherwise
|
|
6
|
+
# someone with a plain "is this the intended behavior?" has no route in at all.
|
|
7
|
+
blank_issues_enabled: false
|
|
8
|
+
|
|
9
|
+
contact_links:
|
|
10
|
+
- name: Question or discussion
|
|
11
|
+
url: https://github.com/Daily-Nerd/Scar/discussions
|
|
12
|
+
about: "Not sure it's a bug? Asking how something is meant to work? Start here — questions get answered faster than they do in issues."
|
|
13
|
+
- name: Documentation
|
|
14
|
+
url: https://daily-nerd.github.io/Scar/
|
|
15
|
+
about: Quickstart, concepts, agent setup, and the methodology behind the measurements.
|
|
16
|
+
- name: Agent-readable docs (llms.txt)
|
|
17
|
+
url: https://daily-nerd.github.io/Scar/llms.txt
|
|
18
|
+
about: If you are an AI agent reading this, start here rather than scraping the site.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: A capability Scar should have, or a pain it should remove
|
|
3
|
+
title: "feat: "
|
|
4
|
+
labels: ["enhancement", "type:feature"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
**A maintainer must add `status:approved` to this issue before a PR can be
|
|
10
|
+
opened against it.** CI enforces that, so please let the idea get a verdict
|
|
11
|
+
before writing code against it.
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: problem
|
|
15
|
+
attributes:
|
|
16
|
+
label: Problem
|
|
17
|
+
description: |
|
|
18
|
+
The pain, as concretely as you can. What happens today that shouldn't, or
|
|
19
|
+
can't happen that should? Prefer a real case you hit over a hypothetical.
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: solution
|
|
25
|
+
attributes:
|
|
26
|
+
label: Proposed solution
|
|
27
|
+
description: How it would work from your side — commands, flags, output, behavior. Rough is fine.
|
|
28
|
+
validations:
|
|
29
|
+
required: true
|
|
30
|
+
|
|
31
|
+
- type: textarea
|
|
32
|
+
id: alternatives
|
|
33
|
+
attributes:
|
|
34
|
+
label: Alternatives considered
|
|
35
|
+
description: Workarounds you use today, or other shapes this could take.
|
|
36
|
+
validations:
|
|
37
|
+
required: false
|
|
38
|
+
|
|
39
|
+
- type: dropdown
|
|
40
|
+
id: area
|
|
41
|
+
attributes:
|
|
42
|
+
label: Area
|
|
43
|
+
options:
|
|
44
|
+
- Anchoring and matching (path, pattern, symbol, fingerprint, command)
|
|
45
|
+
- Hooks and agent integration
|
|
46
|
+
- CLI surface and output
|
|
47
|
+
- Harvest and authoring
|
|
48
|
+
- Lint, orphan detection, lifecycle
|
|
49
|
+
- Measurement — firing log, stats, compliance
|
|
50
|
+
- Docs and website
|
|
51
|
+
- Packaging and install
|
|
52
|
+
- Other / not sure
|
|
53
|
+
validations:
|
|
54
|
+
required: false
|
|
55
|
+
|
|
56
|
+
- type: markdown
|
|
57
|
+
attributes:
|
|
58
|
+
value: |
|
|
59
|
+
### Before you write it up
|
|
60
|
+
|
|
61
|
+
Two things this project is deliberate about, worth knowing so a proposal
|
|
62
|
+
does not get bounced for a reason that isn't obvious:
|
|
63
|
+
|
|
64
|
+
- **Machine-readable output is a contract.** The `--json` payloads are
|
|
65
|
+
documented in `SPEC.md` §9. Adding keys is fine; removing or retyping a
|
|
66
|
+
documented key is breaking.
|
|
67
|
+
- **Numbers are refused rather than flattered.** Where a metric's
|
|
68
|
+
denominator is absent, Scar reports `null` instead of a number the data
|
|
69
|
+
cannot support. Proposals that would report a confident number from thin
|
|
70
|
+
evidence tend to get pushed back on for that reason alone.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Closes #
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
CI gates this PR (.github/workflows/pr-validation.yml). All of these are checked
|
|
5
|
+
BEFORE review, so getting them right up front saves a round-trip:
|
|
6
|
+
|
|
7
|
+
1. The body links an issue: `Closes #N` / `Fixes #N` / `Resolves #N`.
|
|
8
|
+
"Refs #N" does NOT satisfy this check — the regex only accepts those three
|
|
9
|
+
verbs. If a PR is one stage of a multi-PR issue and you don't want merging it
|
|
10
|
+
to close the issue, say so in the body and reopen the issue after merge.
|
|
11
|
+
|
|
12
|
+
2. That linked issue carries the `status:approved` label. A maintainer adds it.
|
|
13
|
+
If it isn't there yet, the check fails — wait for approval rather than
|
|
14
|
+
opening the PR early.
|
|
15
|
+
|
|
16
|
+
3. Exactly ONE `type:*` label on the PR. Note the names, they are not the same
|
|
17
|
+
as the conventional-commit types:
|
|
18
|
+
type:feature type:fix type:docs type:refactor type:chore
|
|
19
|
+
("type:feat" does not exist and will not apply.)
|
|
20
|
+
|
|
21
|
+
4. Conventional title: `type(scope): description`. Squash-merge makes this the
|
|
22
|
+
commit subject on main, so release-please reads THIS, not your local commit
|
|
23
|
+
messages. A breaking change needs the `!` in the title (`feat!:`,
|
|
24
|
+
`fix(scope)!:`) — a local commit footer does not survive the squash.
|
|
25
|
+
|
|
26
|
+
5. Branch name matches `type/description`, lowercase, `[a-z0-9._-]` only:
|
|
27
|
+
feat fix chore docs style refactor perf test build ci revert
|
|
28
|
+
Pick it from the KIND of change, not the content area — `research/foo` fails.
|
|
29
|
+
A PR's head branch cannot be retargeted, so a wrong name means closing and
|
|
30
|
+
reopening the PR. Worse, renaming a branch mid-flight can resurrect the old
|
|
31
|
+
ref. Get the name right before the first push.
|
|
32
|
+
|
|
33
|
+
Two exemptions, both automatic:
|
|
34
|
+
- Scars-only PRs (every changed file under `.scars/`) skip gates 1 and 2 —
|
|
35
|
+
human sign-off already happened at `scar promote`. Gates 3-5 still apply.
|
|
36
|
+
- release-please branches skip the whole job.
|
|
37
|
+
|
|
38
|
+
Seeing NO checks at all, rather than failing ones? That is not a broken
|
|
39
|
+
workflow. Pull requests from forks and from bots wait on a maintainer to
|
|
40
|
+
approve the Actions run, and until someone clicks, zero check-runs is the
|
|
41
|
+
expected state. Nothing on your side to fix — say so in a comment if it sits.
|
|
42
|
+
-->
|
|
43
|
+
|
|
44
|
+
## What
|
|
45
|
+
|
|
46
|
+
## Why
|
|
47
|
+
|
|
48
|
+
## Tests
|
|
49
|
+
|
|
50
|
+
<!--
|
|
51
|
+
What you ran and what it proves. New behavior needs a test that failed before
|
|
52
|
+
the change.
|
|
53
|
+
|
|
54
|
+
Run before pushing — CI runs all three:
|
|
55
|
+
|
|
56
|
+
uv run pytest
|
|
57
|
+
uv run scar lint # a gate pytest does NOT cover: dead anchors, rot, ReDoS
|
|
58
|
+
uv run ruff check src/scar tests
|
|
59
|
+
|
|
60
|
+
If you touched a `--json` payload, re-read `SPEC.md` §9 first. Those keys are a
|
|
61
|
+
published contract: adding is fine, removing or retyping a documented key is
|
|
62
|
+
breaking, and `tests/test_json_contract.py` will tell you which.
|
|
63
|
+
-->
|
|
64
|
+
|
|
65
|
+
## Checklist
|
|
66
|
+
|
|
67
|
+
- [ ] Linked issue above has `status:approved`
|
|
68
|
+
- [ ] Exactly one `type:*` label applied
|
|
69
|
+
- [ ] `uv run pytest`, `uv run scar lint` and `ruff` pass locally
|
|
70
|
+
- [ ] If an approach was tried and abandoned here, a candidate scar was written to `.scars/candidates/`
|
|
@@ -39,15 +39,46 @@ jobs:
|
|
|
39
39
|
# fixture (tests/conftest.py) fails loudly here instead of silently
|
|
40
40
|
# writing into a real ~/.claude/scar-state firing log. 92 of 105 records
|
|
41
41
|
# were once pytest artifacts — see website/docs/methodology.md (#228).
|
|
42
|
+
# Coverage is collected across BOTH legs and combined (--cov-append),
|
|
43
|
+
# not just the richer one: the no-symbols run is the only place the
|
|
44
|
+
# "symbols unavailable" fallbacks execute, so measuring the extras run
|
|
45
|
+
# alone would report those branches as dead when they are the default
|
|
46
|
+
# install's real path. One .coverage file, written here, appended below,
|
|
47
|
+
# rendered to XML at the end.
|
|
42
48
|
- name: Run tests
|
|
43
49
|
run: |
|
|
44
50
|
mkdir -p "$RUNNER_TEMP/fake-home"
|
|
45
|
-
HOME="$RUNNER_TEMP/fake-home" uv run pytest -q
|
|
51
|
+
HOME="$RUNNER_TEMP/fake-home" uv run pytest -q \
|
|
52
|
+
--cov=scar --cov-report= --junitxml=junit-core.xml
|
|
46
53
|
|
|
47
54
|
- name: Run tests (with symbols extra)
|
|
48
55
|
run: |
|
|
49
56
|
mkdir -p "$RUNNER_TEMP/fake-home"
|
|
50
|
-
HOME="$RUNNER_TEMP/fake-home" uv run --extra symbols pytest -q
|
|
57
|
+
HOME="$RUNNER_TEMP/fake-home" uv run --extra symbols pytest -q \
|
|
58
|
+
--cov=scar --cov-append --cov-report=xml --junitxml=junit-symbols.xml
|
|
59
|
+
|
|
60
|
+
# Reporting only — no coverage threshold gates the build, and
|
|
61
|
+
# fail_ci_if_error stays false so a missing or rotated CODECOV_TOKEN
|
|
62
|
+
# degrades to "no coverage comment" rather than a red build on a PR
|
|
63
|
+
# that changed nothing about the tests (#273).
|
|
64
|
+
- name: Upload test results to Codecov
|
|
65
|
+
if: ${{ matrix.python-version == '3.13' && !cancelled() }}
|
|
66
|
+
uses: codecov/test-results-action@v1
|
|
67
|
+
with:
|
|
68
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
69
|
+
files: ./junit-core.xml,./junit-symbols.xml
|
|
70
|
+
flags: py${{ matrix.python-version }}
|
|
71
|
+
fail_ci_if_error: false
|
|
72
|
+
|
|
73
|
+
- name: Upload coverage to Codecov
|
|
74
|
+
if: ${{ matrix.python-version == '3.13' && !cancelled() }}
|
|
75
|
+
uses: codecov/codecov-action@v7
|
|
76
|
+
with:
|
|
77
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
78
|
+
slug: Daily-Nerd/Scar
|
|
79
|
+
files: ./coverage.xml
|
|
80
|
+
flags: py${{ matrix.python-version }}
|
|
81
|
+
fail_ci_if_error: false
|
|
51
82
|
|
|
52
83
|
# Dogfood: the repo's own scar graph must always parse and lint clean.
|
|
53
84
|
# A malformed scar silently never fires (the daimon 0004 incident) —
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 18
|
|
3
|
+
type: landmine
|
|
4
|
+
title: cli.py subparsers register via _add(), not add_parser — and a test's drift gate parses that exact call shape
|
|
5
|
+
severity: medium
|
|
6
|
+
confidence: 0.8
|
|
7
|
+
created: 2026-08-29
|
|
8
|
+
authors: ["claude-code", "Kibukx"]
|
|
9
|
+
anchors:
|
|
10
|
+
- path: src/scar/cli.py
|
|
11
|
+
- path: tests/test_json_contract.py
|
|
12
|
+
- pattern: "_add\(\s*sub,"
|
|
13
|
+
evidence:
|
|
14
|
+
- pr: 257
|
|
15
|
+
- issue: 255
|
|
16
|
+
- issue: 259
|
|
17
|
+
expires:
|
|
18
|
+
condition: "subcommand registration stops going through a wrapper, or the drift gate stops parsing source text"
|
|
19
|
+
review_after: 2027-08-29
|
|
20
|
+
status: active
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
Every subcommand is registered through the local `_add()` wrapper (which wires
|
|
24
|
+
RichHelpFormatter), so `add_parser` appears only twice in cli.py — inside that
|
|
25
|
+
helper's own definition. Grepping for `add_parser` to enumerate the CLI surface
|
|
26
|
+
returns nothing useful and reads as "no subcommands here". Search for
|
|
27
|
+
`_add(sub, "name"` instead.
|
|
28
|
+
|
|
29
|
+
The coupling: `tests/test_json_contract.py::test_spec_documents_every_json_subcommand`
|
|
30
|
+
parses cli.py as TEXT with that regex to prove SPEC §9.3 documents every
|
|
31
|
+
`--json` command. Renaming `_add`, changing its argument order, or building
|
|
32
|
+
parsers in a loop makes the regex match nothing — the test then compares an
|
|
33
|
+
empty set against a populated SPEC table and fails with a confusing message
|
|
34
|
+
that points at the spec rather than at the refactor. If you change the
|
|
35
|
+
registration shape, update that helper in the same commit (PR #257).
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
id:
|
|
2
|
+
id: 19
|
|
3
3
|
type: deadend
|
|
4
4
|
title: A token in a scar body cannot prove hook delivery — the agent can just read the file
|
|
5
5
|
severity: high
|
|
6
6
|
confidence: 0.95
|
|
7
7
|
created: 2026-08-28
|
|
8
|
-
authors: ["claude-code"]
|
|
8
|
+
authors: ["claude-code", "Kibukx"]
|
|
9
9
|
anchors:
|
|
10
10
|
- path: src/scar/codex.py
|
|
11
11
|
- path: src/scar/hooks.py
|
|
12
|
-
# No pattern anchor on purpose: the candidate phrasings ("verification
|
|
13
|
-
# token", "delivery proof") matched nothing but this file, and "A/B" alone
|
|
14
|
-
# is too loose to earn one. Path anchors are the honest fire condition —
|
|
15
|
-
# this hazard applies whenever someone edits a hook adapter and wants to
|
|
16
|
-
# prove it works. See scar #35 on ghost patterns that only self-match.
|
|
17
12
|
evidence:
|
|
18
13
|
- pr: 244
|
|
19
14
|
- pr: 247
|
|
@@ -21,7 +16,7 @@ evidence:
|
|
|
21
16
|
expires:
|
|
22
17
|
condition: "a delivery check exists that observes hook execution directly (firing-log row or marker) rather than model output"
|
|
23
18
|
review_after: 2027-02-28
|
|
24
|
-
status:
|
|
19
|
+
status: active
|
|
25
20
|
---
|
|
26
21
|
|
|
27
22
|
Putting a private token in an active scar's body and looking for it in the
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0
|
|
3
|
+
type: landmine
|
|
4
|
+
title: A health check that watches one direction of pipeline failure leaves the flattering direction unwatched
|
|
5
|
+
severity: high
|
|
6
|
+
confidence: 0.9
|
|
7
|
+
created: 2026-08-30
|
|
8
|
+
authors: ["claude-code"]
|
|
9
|
+
anchors:
|
|
10
|
+
- path: src/scar/cli.py
|
|
11
|
+
- path: src/scar/hooks.py
|
|
12
|
+
- pattern: "instrument_disconnected|posttool_silent|verdict_observed"
|
|
13
|
+
evidence:
|
|
14
|
+
- issue: 277
|
|
15
|
+
- issue: 237
|
|
16
|
+
expires:
|
|
17
|
+
condition: "the pipeline stops having two independently-installable halves"
|
|
18
|
+
status: candidate
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
The precheck and posttool hooks install separately and fail separately. #237
|
|
22
|
+
added a guard for one of those failures: violations recorded with zero precheck
|
|
23
|
+
rows means the precheck half is dead. That guard was correct and it shipped
|
|
24
|
+
after a real four-week outage.
|
|
25
|
+
|
|
26
|
+
Nobody wrote the mirror, and the mirror was the dangerous one. Posttool used to
|
|
27
|
+
`return 0` before logging anything when it found no violation, so a clean edit
|
|
28
|
+
left no trace. That made a dead posttool hook produce zero violations against a
|
|
29
|
+
full firing count, which is byte-identical to perfect compliance. The guarded
|
|
30
|
+
direction was the one that made the numbers look bad. The unguarded direction
|
|
31
|
+
was the one that made them look good, and it stayed unguarded for months.
|
|
32
|
+
|
|
33
|
+
Two rules follow, and both are load-bearing. First, when a pipeline has halves
|
|
34
|
+
that fail independently, a health check for one half is not a health check.
|
|
35
|
+
Ask which failure the existing guard CANNOT see, and assume it is the flattering
|
|
36
|
+
one until proven otherwise. Second, absence of a record is only evidence when
|
|
37
|
+
the writer emits a record in the negative case too. Posttool now logs on the
|
|
38
|
+
clean path whenever a violation was possible, and that is the only reason
|
|
39
|
+
`verdicts_unresolved` can mean anything.
|
|
40
|
+
|
|
41
|
+
Do not "simplify" posttool by restoring the early return on no-violation. It
|
|
42
|
+
looks like dead work and it is the entire mechanism.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0
|
|
3
|
+
type: landmine
|
|
4
|
+
title: A posttool change in hooks.py does not reach codex.py or cascade.py, which carry their own copy of the same logic
|
|
5
|
+
severity: high
|
|
6
|
+
confidence: 0.8
|
|
7
|
+
created: 2026-09-02
|
|
8
|
+
authors: ["claude-code"]
|
|
9
|
+
anchors:
|
|
10
|
+
- path: src/scar/hooks.py
|
|
11
|
+
- path: src/scar/codex.py
|
|
12
|
+
- path: src/scar/cascade.py
|
|
13
|
+
violation: "if not violations:"
|
|
14
|
+
evidence:
|
|
15
|
+
- issue: 277
|
|
16
|
+
- issue: 293
|
|
17
|
+
- pr: 297
|
|
18
|
+
expires:
|
|
19
|
+
condition: "the three posttool paths share one implementation, or the adapters delegate to hooks.posttool"
|
|
20
|
+
review_after: 2026-12-01
|
|
21
|
+
status: candidate
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
The posttool verdict logic exists three times: `hooks.posttool` for Claude
|
|
25
|
+
Code, `codex.posttool` for Codex, and `cascade.post_write_code` for Windsurf.
|
|
26
|
+
They are copies, not callers. #277 fixed the flattering-direction blind spot
|
|
27
|
+
(a clean edit must still write a verdict row, or a dead hook reads as perfect
|
|
28
|
+
compliance) in hooks.py only. The adapters kept the pre-#277 early return, so
|
|
29
|
+
on Codex one clean armed edit trips the "broken install" warning on a healthy
|
|
30
|
+
install (#293). The #277 test suite asserted the Codex row SHAPE and never
|
|
31
|
+
exercised the Codex clean path, so green CI proved nothing about the copies.
|
|
32
|
+
|
|
33
|
+
When you change what a posttool writes, reads, or skips in hooks.py, open
|
|
34
|
+
codex.py and cascade.py in the same PR and make the same change, or make them
|
|
35
|
+
delegate. A bare `if not violations: return` in an adapter is the exact shape
|
|
36
|
+
that reintroduces the blind spot, which is why it is the tripwire here.
|
{scar_cli-0.20.0/src/scar/skills/scar-authoring/assets → scar_cli-0.22.0/.scars}/template.md
RENAMED
|
@@ -10,7 +10,7 @@ title: One line, searchable, says the constraint
|
|
|
10
10
|
severity: medium # low | medium | high | critical
|
|
11
11
|
confidence: 0.7 # 0..1 — how sure are we this still holds
|
|
12
12
|
created: 1970-01-01
|
|
13
|
-
authors: ["claude-code"] #
|
|
13
|
+
authors: ["claude-code"] # who DRAFTED it; the promoting human goes in promoted_by, written by promote
|
|
14
14
|
anchors:
|
|
15
15
|
- path: src/module/ # file or directory this protects
|
|
16
16
|
- pattern: "regex" # optional: fires when matching code appears in ANY new/edited file
|
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.22.0](https://github.com/Daily-Nerd/Scar/compare/v0.21.0...v0.22.0) (2026-09-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **lint:** escalate a chronically-firing scar into an explicit review flag ([#276](https://github.com/Daily-Nerd/Scar/issues/276)) ([e26884b](https://github.com/Daily-Nerd/Scar/commit/e26884b0b01938420c137673e1c9e01eb4c6dc63))
|
|
9
|
+
* **promote:** record whether promoted_by was typed or read from git config ([#298](https://github.com/Daily-Nerd/Scar/issues/298)) ([bcdc4d7](https://github.com/Daily-Nerd/Scar/commit/bcdc4d7b6d82c5d1b9b38365648f23ed45050064))
|
|
10
|
+
* **reanchor:** record an applied rewrite as an evidence note on the scar ([#299](https://github.com/Daily-Nerd/Scar/issues/299)) ([2aa1d12](https://github.com/Daily-Nerd/Scar/commit/2aa1d12230e7c8b379dcd967a780e0c2cf4a3b2e))
|
|
11
|
+
* **stats:** record blocking capability on the firing row ([#281](https://github.com/Daily-Nerd/Scar/issues/281)) ([a341b48](https://github.com/Daily-Nerd/Scar/commit/a341b48eb365bd8522175570f72b767af1b50c37))
|
|
12
|
+
* **stats:** record context size on the firing row ([#283](https://github.com/Daily-Nerd/Scar/issues/283)) ([99ba9c3](https://github.com/Daily-Nerd/Scar/commit/99ba9c3e8e63aa64ed2c925cba4b4a59895139e0))
|
|
13
|
+
* **stats:** record the match census before top_k truncates it ([#289](https://github.com/Daily-Nerd/Scar/issues/289)) ([715e42c](https://github.com/Daily-Nerd/Scar/commit/715e42c4f73f512b80854f6d68152c5108256246))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **hooks:** Codex and Windsurf posttool record a clean verdict too ([#297](https://github.com/Daily-Nerd/Scar/issues/297)) ([823af3c](https://github.com/Daily-Nerd/Scar/commit/823af3c8e463d6ee89990de0f0fe8606e5dde86f)), closes [#293](https://github.com/Daily-Nerd/Scar/issues/293)
|
|
19
|
+
* **promote:** record who vouched in its own field, not inside authors ([#290](https://github.com/Daily-Nerd/Scar/issues/290)) ([d1e649a](https://github.com/Daily-Nerd/Scar/commit/d1e649a03ef7a76349da48f7772ee4755c332009)), closes [#287](https://github.com/Daily-Nerd/Scar/issues/287)
|
|
20
|
+
* **stats:** make a dead posttool hook distinguishable from compliance ([#280](https://github.com/Daily-Nerd/Scar/issues/280)) ([13f0b6a](https://github.com/Daily-Nerd/Scar/commit/13f0b6ae255dfb1e89f0f61296f4f25d5890acda))
|
|
21
|
+
* **stats:** record why a scar was demoted, not just that it was ([#288](https://github.com/Daily-Nerd/Scar/issues/288)) ([d6dafba](https://github.com/Daily-Nerd/Scar/commit/d6dafbab8ed389815e28535fdc929cd906f657ef)), closes [#284](https://github.com/Daily-Nerd/Scar/issues/284)
|
|
22
|
+
* **stats:** stop counting a command firing as an observed edit ([#300](https://github.com/Daily-Nerd/Scar/issues/300)) ([7abeeed](https://github.com/Daily-Nerd/Scar/commit/7abeeedba8b43634c6d4ccfafbf7eac7fd173269)), closes [#294](https://github.com/Daily-Nerd/Scar/issues/294)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Documentation
|
|
26
|
+
|
|
27
|
+
* **format:** update the stale veritrail link to vitni ([#269](https://github.com/Daily-Nerd/Scar/issues/269)) ([a842449](https://github.com/Daily-Nerd/Scar/commit/a842449ca0d2eb2fde9310dcef244c299316a84f)), closes [#268](https://github.com/Daily-Nerd/Scar/issues/268)
|
|
28
|
+
* **stats:** state that the armed-window number needs git archaeology ([#291](https://github.com/Daily-Nerd/Scar/issues/291)) ([4097081](https://github.com/Daily-Nerd/Scar/commit/4097081b40fa56bcb255dbda8bdf03f8ac0ab203)), closes [#285](https://github.com/Daily-Nerd/Scar/issues/285)
|
|
29
|
+
|
|
30
|
+
## [0.21.0](https://github.com/Daily-Nerd/Scar/compare/v0.20.0...v0.21.0) (2026-08-29)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Features
|
|
34
|
+
|
|
35
|
+
* **stats:** add --since/--until so a window is a first-class operation ([#263](https://github.com/Daily-Nerd/Scar/issues/263)) ([f1b262b](https://github.com/Daily-Nerd/Scar/commit/f1b262b600394d206022ce7f129a168f518254e1)), closes [#258](https://github.com/Daily-Nerd/Scar/issues/258)
|
|
36
|
+
* **stats:** record which fired scars were violation-armed ([#267](https://github.com/Daily-Nerd/Scar/issues/267)) ([206d6af](https://github.com/Daily-Nerd/Scar/commit/206d6afff0094b72ec01ff004a274442738617d0)), closes [#266](https://github.com/Daily-Nerd/Scar/issues/266)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Bug Fixes
|
|
40
|
+
|
|
41
|
+
* **codex:** let the duplicate-channel warning be silenced ([#253](https://github.com/Daily-Nerd/Scar/issues/253)) ([e060656](https://github.com/Daily-Nerd/Scar/commit/e06065631f9fd3054d7d86d1a528d464a15af432)), closes [#252](https://github.com/Daily-Nerd/Scar/issues/252)
|
|
42
|
+
* **match:** scan whole file bodies for pattern liveness ([#262](https://github.com/Daily-Nerd/Scar/issues/262)) ([fe177ca](https://github.com/Daily-Nerd/Scar/commit/fe177ca55bd05dc69a9a486b89bb8dca0e24e514)), closes [#259](https://github.com/Daily-Nerd/Scar/issues/259)
|
|
43
|
+
* **stats:** report the applied window in the --all-repos payload ([#265](https://github.com/Daily-Nerd/Scar/issues/265)) ([b0e8c1f](https://github.com/Daily-Nerd/Scar/commit/b0e8c1f4a138b2c8847acdd1e7ba8c09269a4069)), closes [#264](https://github.com/Daily-Nerd/Scar/issues/264)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Documentation
|
|
47
|
+
|
|
48
|
+
* **spec:** publish a stability contract for the nine --json payloads ([#257](https://github.com/Daily-Nerd/Scar/issues/257)) ([c3e5c1b](https://github.com/Daily-Nerd/Scar/commit/c3e5c1b94060fc551aaece7ad98085464b9603d7)), closes [#255](https://github.com/Daily-Nerd/Scar/issues/255)
|
|
49
|
+
|
|
3
50
|
## [0.20.0](https://github.com/Daily-Nerd/Scar/compare/v0.19.0...v0.20.0) (2026-08-28)
|
|
4
51
|
|
|
5
52
|
|
|
@@ -41,11 +41,14 @@ is deliberate: consumers in hook hot-paths parse with zero dependencies.
|
|
|
41
41
|
| `severity` | yes | `low` \| `medium` \| `high` \| `critical` | ranking input |
|
|
42
42
|
| `confidence` | yes | float 0..1 | static authored ranking weight; dynamic decay deferred (SPEC §5, issue #95) |
|
|
43
43
|
| `created` | yes | ISO date | |
|
|
44
|
-
| `authors` | yes | inline list | agents as `"claude-code"` etc
|
|
44
|
+
| `authors` | yes | inline list | who drafted it: agents as `"claude-code"` etc. The reviewer is no longer appended here |
|
|
45
|
+
| `promoted_by` | active scars | string | the human who promoted it. Written only by `scar promote`, which overwrites anything a candidate carried. Empty on scars promoted before the field existed, and never inferred from `authors` |
|
|
46
|
+
| `promoted_by_source` | optional | `explicit` \| `git-config` | whether `promoted_by` came from `--reviewer` or from `git config user.name`. Written only alongside `promoted_by`, never on its own. Absent on scars promoted before the field existed |
|
|
45
47
|
| `anchors` | yes, ≥1 | list of `- path:`, `- pattern:`, `- symbol:`, and/or `- command:` | §4 |
|
|
46
48
|
| `evidence` | recommended | list of `- commit:`/`- pr:`/`- issue:`/`- incident:`/`- note:`/`- url:` | absent ⇒ challengeable on sight; `issue:`/`url:` are durable forms that survive squash-merge |
|
|
47
49
|
| `expires.condition` | recommended | quoted string | what change obsoletes this scar |
|
|
48
50
|
| `expires.review_after` | recommended | ISO date | forces periodic freshness contact |
|
|
51
|
+
| `expires.review_after_firings` | optional | non-negative integer | forces a review once the scar has fired this many times since its last revision; absent ⇒ per-type default (`landmine` 10, `fence` 15, `deadend` disabled), `0` ⇒ never escalate |
|
|
49
52
|
| `status` | yes | `candidate` \| `active` \| `challenged` \| `archived` \| `orphaned` \| `template` | lifecycle §5 |
|
|
50
53
|
| `receipt_id` | reserved | string ref | **reserved — not yet parsed.** Optional pointer to a cryptographic provenance receipt; see note below. |
|
|
51
54
|
|
|
@@ -54,7 +57,7 @@ trust model is social by design (git history, `authors`, evidence-by-reference);
|
|
|
54
57
|
that is sufficient within one repo or org. It does **not** carry across orgs that
|
|
55
58
|
share no git history — the future cross-org / org-graph layer where "this dead end
|
|
56
59
|
hit N teams" must be attributable. `receipt_id` reserves the slot for a signed,
|
|
57
|
-
content-addressed receipt (e.g. [
|
|
60
|
+
content-addressed receipt (e.g. [vitni](https://github.com/Daily-Nerd/vitni))
|
|
58
61
|
bound to an authorship (`scar_draft`) or promotion event. No tool emits, requires,
|
|
59
62
|
or validates it today, and the line-wise parser ignores it like any unknown key —
|
|
60
63
|
so existing scars are unaffected. It will not become required in v0.x.
|