feat(source-control): well-known default path for neutral convention SSOT (F1–F4) - #1185
Conversation
…SSOT (F1-F4) Resolve the neutral commit-convention SSOT by a fixed 3-rung precedence, identical on the drafting and enforcement surfaces: explicit convention_source pointer > well-known docs/conventions/source-control/commit-convention.yml > markdown-H2. The common case now reads ONE tool-agnostic file with no markdown pointer-parse and nothing in agent-rewritable prose to sever. Full back-compat. - F2: well-known default path in lib/resolve-convention-pattern.sh (+ synced guardrails mirror, guardrails 0.13.0 -> 0.14.0) and config-resolution.md. - F1: setup recommends the neutral SSOT as the default when a second enforcement consumer (commit-msg hook / CI title check) is detected. - F3: setup check gains drift probes (broken pointer/neutral file -> FAIL; resolved neutral file shadowing stale markdown-H2 -> WARN). - F4: neutral-YAML preamble trimmed to a 1-2 line header. Design + re-anchor rationale: docs/topics/commit-convention-well-known-path/. source-control 0.24.0 -> 0.25.0. Closes #1184 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 4m 16s —— View job Code Review: feat(source-control): well-known default path for neutral convention SSOT (F1–F4)
SummaryOverall: LGTM with minor observations. The implementation is correct, security-hardened, and thoroughly documented. The 3-rung precedence is consistently mirrored across the resolver and all documentation surfaces, and the fail-closed contract is maintained for the well-known path. Minor observations below, none of which block merge. Core resolver logic (
|
| Check | Result |
|---|---|
Symlink file escape (-L test) |
✓ Caught, disabled |
Symlinked directory segment (pwd -P canon check) |
✓ Caught, disabled |
POSIX absolute paths (/*) |
✓ Rejected |
Windows drive-letter paths ([A-Za-z]:*) |
✓ Rejected |
.. traversal (*..*) |
✓ Rejected |
| Non-posix-ere dialect | ✓ Fail-closed |
grep injection in yaml_value / check_neutral_key |
✓ All k values are hardcoded literals (subject_pattern, pr_title_pattern, dialect, convention_source) |
Diagnostic message cosmetics (minor)
When the well-known path fails (e.g., wrong dialect), the error still says:
resolve-convention-pattern: convention_source file declares dialect 'pcre'; enforcement disabled.
A user whose repo has docs/conventions/source-control/commit-convention.yml but no explicit ## convention_source pointer will see a message referencing convention_source they never set. Functionally correct (enforcement is disabled as intended), but could prompt a confused "I never wrote convention_source?" question.
A small prefix like well-known convention file vs convention_source file would distinguish the two origins without changing the exit path. Not a blocker — the F3 check drift probe will surface this condition explicitly with better context before it hits a blocked commit in practice.
Test coverage (lib/resolve-convention-pattern.test.sh lines 279–330)
The new section covers the cases that matter:
| Test | Coverage |
|---|---|
| Well-known present, no pointer, no markdown → resolves | ✓ |
| Well-known + markdown → well-known wins (rung 2 > 3) | ✓ |
| Explicit pointer + well-known → explicit wins (rung 1 > 2) | ✓ |
| Well-known with broken dialect → exit 1 (fail closed) | ✓ |
| Well-known with empty key + stale markdown → exit 1 (fail closed) | ✓ |
| No well-known, no pointer, markdown present → markdown back-compat | ✓ |
| Well-known file omits a key → per-key markdown fallback | ✓ |
There is no dedicated test for a symlinked well-known file — the existing symlink tests at lines 258–277 cover the explicit-pointer path. The general symlink guard in the resolver is shared and path-agnostic, so the behavior is correct; it's just not exercised for the well-known rung specifically. Worth a TODO if the test suite ever grows a CI symlink fixture.
Minor: the PR description says "8 well-known-path cases" but counting assert_eq/assert_exit calls in the new section yields 9 assertions (the broken-dialect and empty-key scenarios each emit two assertions). Not a bug.
F1 / F3 in SKILL.md and apply-convention.md
F1 (recommend neutral SSOT when second consumer detected) is correctly gated on inference step 2's hook detection, not on file presence — the gotcha section at line 209 ("Gate inference on the resolved value, never file presence") applies symmetrically here. The text at SKILL.md line 162–166 and apply-convention.md lines 344–348 are consistent.
F3 drift probes (SKILL.md lines 91–105): the two-condition design is sound. The WARN condition ("neutral file resolves AND markdown still carries the same key") correctly points at apply to retire the duplicate rather than silently inheriting the stale value. The FAIL condition ("broken pointer/neutral file") closes the gap where enforcement was silently disabled.
Cross-surface consistency
The 3-rung precedence is stated identically in:
lib/resolve-convention-pattern.sh(enforcement resolver, both source and guardrails mirror)docs/conventions/commit-convention/README.mdplugins/source-control/reference/config-resolution.md(drafting resolver)SKILL.md
No drift between surfaces. ✓
Guardrails mirror (plugins/guardrails/hooks/resolve-convention-pattern.sh) is byte-identical to the lib source. ✓
Version bumps are appropriate: source-control 0.24.0 → 0.25.0 (new feature) and guardrails 0.13.0 → 0.14.0 (forced by resolver change). ✓
|
Claude finished @kyle-sexton's task in 5m 2s —— View job Security Review — PR #1185
SummaryNo CRITICAL or IMPORTANT issues. The security posture of the resolver is strong: the new well-known-path probe inherits all existing safety gates (absolute-path rejection, SUGGESTION — Glob metacharacter expansion in canonical-directory containment checkConfidence: LOW · Pre-existing; newly exercised by the well-known-path code path this PR adds.
if [[ -z "$canon_root" || -z "$canon_dir" || "$canon_dir/" != "$canon_root/"* ]]; thenIn Exploitation chain for the well-known path (new in this PR):
Why confidence is LOW: Safe alternative — string prefix comparison without glob expansion: canon_prefix="${canon_root}/"
if [[ -z "$canon_root" || -z "$canon_dir" || \
"${canon_dir:0:${#canon_prefix}}" != "$canon_prefix" ]]; thenThis is a pure string-prefix test; no characters in Everything else reviewed — no issues
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d84323f3ce
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…harden canon-prefix (review) Address PR #1185 review findings: - Codex P1: the well-known rung activated on mere file existence, so an untracked or gitignored file at docs/conventions/source-control/commit-convention.yml could silently override tracked team policy (policy-floor violation). Gate the rung on `git ls-files --error-unmatch` — activate only when the file is git-tracked; git absent or file untracked falls through to the markdown H2. Adds two regression tests (untracked -> markdown wins; untracked+no-markdown -> no enforcement). - security-review: replace the `!= "$canon_root/"*` glob match in the symlink canon check with a pure string-prefix comparison, so a glob metacharacter in the physical repo path cannot be interpreted rather than compared literally. - Codex P2: update setup eval case 18 to expect the pointerless well-known default (no convention_source for the default location; pointer only on relocation), matching the new apply-convention default. Mirror resynced; 58/58 resolver tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 31s —— View job Review — PR #1185 (follow-up commit
|
| Test | Behavior verified |
|---|---|
untracked file ignored -> markdown wins |
untracked YAML at well-known path + tracked markdown → markdown wins |
untracked file + no markdown -> exit 1 |
untracked YAML + no markdown → no enforcement (exit 1, not activated) |
The track() helper (git init -q || true && git add -- "$path") is correct: it uses || true so tests don't fail on a re-init, and git add with a relative path in the repo root is precise. One observation: this means six existing well-known tests now require a real git binary at test time — this was already implied by the newrepo fixture pattern but now it's load-bearing. If CI ever runs these in a minimal container without git, the tests that call track() will silently skip (the || true suppresses errors) and then fail because ls-files won't find the file. Worth a note in the test file header if the suite ever runs in such an environment, though not a blocker given this repo's CI setup.
Security suggestion — canon-prefix hardening ✓
lib/resolve-convention-pattern.sh line 194–196:
canon_prefix="$canon_root/"
canon_dir_slash="$canon_dir/"
if [[ -z "$canon_root" || -z "$canon_dir" || "${canon_dir_slash:0:${#canon_prefix}}" != "$canon_prefix" ]]; thenCorrect. The bash substring expansion ${canon_dir_slash:0:${#canon_prefix}} extracts exactly ${#canon_prefix} bytes from canon_dir_slash and compares them as a plain string — no glob characters in canon_root can be interpreted as a pattern. The two intermediate variables are script-level (not function-local), but they're only used in this one check and don't shadow anything. ✓
Guardrails mirror confirmed byte-identical to the lib source. ✓
Codex P2 — eval case 18 ✓
The updated expectation in evals.json now requires:
- The skill writes at the well-known default path without a
convention_sourcepointer. - A pointer is written only for non-default relocation.
- The verification step confirms the file is staged/tracked (not just present), closing the loop with the new policy floor.
The rename from apply-neutral-ssot-migration-retires-duplicates to apply-neutral-ssot-well-known-default-retires-duplicates is precise. ✓
One open cosmetic observation (carry-over, not a blocker)
Noted in the prior review: when the well-known path fails (e.g. wrong dialect), the diagnostic still reads convention_source file declares dialect '...' even when no explicit convention_source was set. The follow-up commit didn't address this — consistent with the prior review's assessment that F3 check surfacing the condition first makes this low-priority. Confirming it remains the only open non-blocking item.
|
Claude finished @kyle-sexton's task in 2m 49s —— View job Security Review — PR #1185 (HEAD: 928cd9b)
SummaryNo CRITICAL or IMPORTANT issues. The fixup commit ( Addressed by 928cd9b
Remaining: SUGGESTION —
|
| Area | Result |
|---|---|
WELL_KNOWN_NEUTRAL constant (line 59) |
readonly; docs/conventions/source-control/commit-convention.yml contains no metacharacters; passes all downstream lexical guards (/* | [A-Za-z]:* | *\\* | *..*) intact |
Well-known probe (-f "$repo_root/$WELL_KNOWN_NEUTRAL") |
Double-quoted — no word splitting, no glob expansion; safe |
git ls-files --error-unmatch -- "$WELL_KNOWN_NEUTRAL" |
$WELL_KNOWN_NEUTRAL is a readonly constant, -- guards against flag injection; git exits non-zero on any failure (git unavailable, not a repo, untracked) — all fail toward the prior markdown-H2 behavior |
Canon-prefix fix (${canon_dir_slash:0:${#canon_prefix}}) |
Pure string substring comparison; no pattern characters in canon_root are ever interpreted as globs |
yaml_value grep -E "^${k}:" |
$k is always a hardcoded literal at all call sites; no user-controlled string reaches the regex |
ERE safety-net grep -E -- "$value" </dev/null |
-- blocks flag injection; /dev/null eliminates ReDoS; exit-code gate handles invalid expressions |
awk -v key="$k" in h2_value |
Value passed as awk variable, not interpolated into awk source |
| Symlink check (line 184) | Regular-file-only requirement on the neutral file stands for both the explicit-pointer and well-known rungs |
| Plugin manifests | Version bumps only (0.24.0→0.25.0, 0.13.0→0.14.0); no new permissions, no new remote dependencies |
| Guardrails mirror | Byte-identical to lib source (confirmed by sync script); the same analysis applies |
| SKILL.md / apply-convention.md | Model instructions with no shell execution surfaces; git rev-parse --show-toplevel usage is trusted and fixed-path |
evals.json |
Eval expectation update only; no execution surface |
|
Also applied the security-review hardening (advisory): the symlink canon check now uses a pure string-prefix comparison instead of a |
…ascade (#1190) ## Summary Renames the marketplace-wide consumer-config layering seam from the clunky three-noun `consumer-config-layering` to **`config-cascade`**. Name chosen via `/naming:name-it-better` (blind 3-lens fan-out): "cascade" (CSS `@layer`/`!important`) is the one established term of art that natively carries **both** per-key override **and** a ratified precedence-inversion — matching the seam's user→team→local + policy-floor model. Runner-ups: `config-layering`, `layer-cascade`, `config-precedence`. - `git mv docs/conventions/consumer-config-layering → config-cascade`. - All **live** references updated (name + path): MIGRATION-PLAYBOOK, PLUGIN-PHILOSOPHY, loop-lane seam, code-tidying (SKILL + docs-prose lane), testing (README + run-e2e SKILL/context), `.gitignore`. - Seam README records the former name (discoverability); CHANGELOG records the rename with **no `contract_version` bump** — name/path only, contract unchanged. - code-tidying `0.7.1→0.7.2`, testing `0.3.1→0.3.2` (patch) so consumers receive the corrected doc-URL. - **Historical** topic docs / CHANGELOGs retain the former name as frozen record (bare-text mentions, not links). **Provenance context:** the rename was gated (issue #1187) on whether the seam was legitimately ratified. Finding: all 12 `docs/conventions/*` seams are PR-introduced across the repo's whole history; `consumer-config-layering` (#692) is unremarkable. The shared `kyle-sexton` identity (human + agents) makes metadata-level "human-ratified vs agent-accreted" undecidable — a **repo-wide** property, not a disqualifier for this seam. The operator's direct direction this session is the ratification. ## Test plan - `lychee --offline './**/*.md'` — **0 errors** (2754 links checked); no dead relative link to the old path. - `grep -rn '](.*conventions/consumer-config-layering' .` — none (no dead relative links). - `scripts/check-changelog-parity.sh --check-bump origin/main` — both bumped plugins have entries. - Remaining `consumer-config-layering` mentions are historical bare-text only (topic PLANs, CHANGELOGs, `.work/`). ## Related - Closes #1188 - Provenance context: #1187 (audit finding recorded above) - Follows #1185 (well-known path, which dogfoods the `docs/conventions/<concern>/` location) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
… both surfaces (#1192) ## Summary #1185's P1 review hardening — the well-known convention-file rung activates only when the file is **git-tracked** — landed only in the enforcement resolver bash. The drafting spec (`config-resolution.md`) and the commit-convention seam README still said rung 2 fires "when that file exists", and config-resolution.md claimed the surfaces were "identical" — false after the fix. **The drift it created:** a repo with an untracked/gitignored well-known file + a different markdown-H2 `subject_pattern` → drafting resolves the untracked file, enforcement skips it → the plugin drafts commits its own gate rejects. Exactly the two-surface divergence the design exists to prevent. Adds the git-tracked requirement + how the drafting reader checks it (`git ls-files --error-unmatch`) to config-resolution.md, the seam README, and the setup SKILL.md gotcha. **Docs-only** — the resolver already enforced tracked; this makes the specs match and "identical on both surfaces" true again. source-control `0.25.0 → 0.25.1`. ## Test plan - `lychee --offline` clean on the three edited docs. - `scripts/check-changelog-parity.sh --check-bump origin/main` — bump has an entry. - No code change (resolver + its 58 tests unchanged); the resolver already required tracked. ## Related - Closes #1191 - Follow-up to #1185 / #163434 (well-known default path) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ion (#1193) ## Summary Closes the #1187 provenance audit with a durable **decision record** in MIGRATION-PLAYBOOK, rather than a forgery-prone gate. **Finding:** in this solo-autonomous setup the operator and every agent act as the same `kyle-sexton` identity, so no in-repo signal (author / reviewer / merger / commit signature) distinguishes human ratification from agent accretion — a **repo-wide property**, not a per-seam defect. All 12 `docs/conventions/*` seams are PR-introduced and cite a ratifying issue/PR; none was silently accreted. **Decision:** decline `CODEOWNERS` / `human-ratified` label / signing gates under the shared identity — an agent satisfies the same gate, so they manufacture *false* assurance (theater). The only real distinguisher is a separate human-only identity/signing key agents don't hold; flagged as an infra option with a revisit trigger, **not imposed**. Interim posture: ratification stays trust-based and visible via cited issues/PRs + operator engagement, with the audit trail as the durable account. Docs-only (marketplace governance doc — no plugin shipped-content change, no version bump). ## Test plan - `lychee --offline docs/MIGRATION-PLAYBOOK.md` — clean. - Decision record follows the doc's existing dated-decision-record format. ## Related - Closes #1187 - Concludes the #163434 work stream (#1185 well-known path, #1190 config-cascade rename, #1192 cross-surface fix) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Treatments from the 2026-08-15 repo-wide /docs-hygiene:audit-noise run (1027 files scanned, 55 scanner candidates, 37 findings after two-worker judgment and a fresh-context adversarial verification pass): - ghost-refs: PR permalinks added beside prune-surviving slice citations (#796, #794, #1459, #1185, #330, #1400), checkout-local caveats on memory-tier ledger refs, stale '.work/ destination' clauses stripped - citations: inline provenance relocated to ## Sources / ## History footers (compress skill, suno drift ledger) - retired-path mentions wrapped in documented opt-out markers where the mention is itself the rule/history being stated - preamble: reference-quadrant 'Why this file exists' collapsed to a one-sentence orientation (song-forms-examples) - enum-list: hardcoded rosters reopened (docs-hygiene README count, session-flow README network roster) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9A7ewGsRVk4KWVUhUcgpq
…back, paragraph-scope markers (#2721) No linked issue ## What this is The apply phase of the first repo-wide `/docs-hygiene:audit-noise` run (2026-08-15): 1,027 tracked markdown files scanned with the skill's own `detect.sh`, 55 scanner candidates judged by two concurrent Opus workers, all actionable verdicts adversarially verified by a fresh-context verifier (54 checked, 50 upheld, 4 overturned — overturns applied). Net: 2 Tier 1 + 30 Tier 2 findings, 24 scanner false positives dismissed, all 33 flagged files passing the existence pre-check. ## Commits - **`docs:` treatments (31 of 32 actionable findings):** ghost-refs get carrying-PR permalinks (#796, #794, #1459, #1185, #330, #1400), checkout-local caveats, or strips; citations relocate to `## Sources`/`## History` footers; retired-path mentions that ARE the stated rule/history get opt-out markers; a Reference-quadrant preamble collapses; hardcoded rosters reopen. Deliberately not edited: `line-brainstorm-prompt.md:182` (roster inside an output-template code fence — accepted as a reviewed hardcode; this PR is the recorded review). - **`feat(docs-hygiene): 0.12.0`:** audit-noise's clean-tree default becomes a confirmation-gated repo-wide offer (blocked when unattended) instead of a silent no-op; `detect.sh`'s opt-out markers now honor the documented paragraph scope (`-line` distinguished; heading also closes scope); Tier 3 explicitly carries no treatment; recurring judgment dismissal grounds codified; carrying/pruning PR numbers sanctioned as durable ghost-ref pointers; `CHANGELOG.md` skipped by basename per the long-documented exemption. Tests 38/38; shellcheck/shfmt/markdownlint/changelog-parity clean. - **`chore:` version bumps** required by the changelog-parity gate for touched plugin trees (session-flow 0.23.5, songwriting 1.4.4) and the regenerated `docs/CATALOG.md`. - **`fix:` fresh-context verification minors** — diff verification returned CLEAN (all six PR-citation claims verified against git history); 6 of its 9 minor observations fixed, 3 recorded as accepted in the PR comments. ## Dispositions — nothing left dangling Completed in this PR: Tier-3 treatment semantics, `-line` marker docs, PR-number pointers, codified dismissal grounds, CHANGELOG basename skip, marker paragraph scope, clean-tree fallback. Filed as issues (from the run + the follow-up `/plugin-quality:audit` of the components this session exercised): - #2730 — `.work/running-retros/` concern-root codification (convention-ownership decision) - #2734 — sibling audit skills adopt the clean-tree fallback - #2739 — cloud-bootstrap installs npm-global tools into an nvm prefix invisible to plugin hooks (markdown lint gate silently lost in cloud sessions; found via this session's hook false-negative) - #2740 — markdown-format notice wording ("skipped for this session" misstates the latch) + probed-PATH diagnostic - #2741 — `detect.sh` per-line subshell forking (~700× grep; root cause of this run's scan timeout) + chunking affordance for the new fallback - #2742 — scanner exemption gaps (frontmatter unimplemented, marker-substring self-trigger, no code-fence awareness, section-state leaks) ## Verification state Fresh-context diff verification: CLEAN. Automated security review: clean at every pushed head. Automated code review: no findings. Local gates green (38/38 script tests, shellcheck/shfmt, markdownlint, changelog parity, plugin validation + catalog). ## Related - Predecessor PR #2696 (closed as premature; carried only the since-reverted ledger commit) - Follow-up issues: #2730, #2734, #2739, #2740, #2741, #2742 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01H9A7ewGsRVk4KWVUhUcgpq --------- Co-authored-by: Claude <noreply@anthropic.com>
Summary
Resolves the neutral commit-convention SSOT (from #1141) by a fixed 3-rung precedence, identical
on the drafting and enforcement surfaces:
convention_sourcepointer — relocation override, path stays repo-owneddocs/conventions/source-control/commit-convention.ymlwhen present — themarketplace's own dogfooded
docs/conventions/<concern>/layout; common case reads ONEtool-agnostic file, no markdown pointer-parse, nothing in agent-rewritable prose to sever
.claude/source-control.md— legacy / back-compatFull back-compat: absent both a pointer and the well-known file, resolution is unchanged.
Findings folded in (inbox item
20260723-163434):lib/resolve-convention-pattern.sh+ synced guardrails mirror +config-resolution.md).setup checkgains drift probes: broken pointer/neutral file → FAIL; resolved neutral file shadowing stale markdown-H2 → WARN.Design + re-anchor rationale (reuse-or-replace, recheck-against-upstream, reason-dont-recite, point-dont-copy):
docs/topics/commit-convention-well-known-path/design-resolution.md.Scope note (honest): F3 closes silent severance for well-known-default repos; a repo that relocates via
convention_sourceand then loses the pointer still falls through per-key to markdown —checksurfaces it, but prevention there is bounded by design.Version bumps: source-control 0.24.0 → 0.25.0; guardrails 0.13.0 → 0.14.0 (forced by the sync
--check-bumpgate — vendored resolver changed).Test plan
bash lib/resolve-convention-pattern.test.sh— 56/56 (added 8 well-known-path cases: resolves-with-no-pointer, wins-over-markdown, explicit-overrides-well-known, fail-closed on broken well-known, per-key markdown fallback, back-compat).scripts/sync-resolve-convention-pattern.sh --check— mirror byte-identical.scripts/sync-resolve-convention-pattern.sh --check-bump origin/main— guardrails bumped.scripts/check-changelog-parity.sh --check-bump origin/main— both CHANGELOGs updated.shellcheckclean on the resolver + mirror.Related
20260723-163434-source-control-setup-convention-default-and-config-surface🤖 Generated with Claude Code