Skip to content

Commit ff24cf9

Browse files
intel352Jon Langevin
andauthored
ADK path canonicalization + write-location transparency + artifact hygiene (v6.5.0) (#75)
* design: ADK path canonicalization + write-location transparency + artifact hygiene (v6.5.0) * design: revise per adversarial review (2C+3I+4m): resolver null-guard, placeholder-aware gate, dedicated CI workflow, authoritative 12-hook list * design: PASS @ adversarial cycle 2 (converged); 2 minors → plan notes * plan: ADK path canonicalization (10 tasks, 1 PR → v6.5.0) * plan: enumerate PR-grouping tasks + keep Task-6 probe gate-clean (printf) * plan: revise per plan-phase adversarial (1C+2I+4m): C-1 test fix, drop scope-lock-claim (11 hooks), session-start/pre-compact anchors, behavioral degradation test * plan: cycle-2 fix — pwd -P resolver (C-2 macOS symlink); verified all 4 resolver cases * plan: PASS @ plan-adversarial cycle 3 (converged) * chore: lock scope for adk-path-canonicalization (alignment passed) * test: ADK path canonicalization resolver+wiring guard [red] * feat(hooks): canonical ADK state-root resolver (git-common-dir anchored) * refactor(hooks): 11 state writers resolve canonical root via shared lib (#70 residual) * docs(retro): read activation log from canonical repo root (#70 residual) * docs(subagents): require a repo-relative Writes: ledger from every subagent (C2) * test(hygiene): forbid operator-home paths in artifacts; fix docs/testing.md leak (C3) * ci: dedicated always-on path-hygiene workflow (C3) * docs(skills): repo-relative-paths rule for committed artifacts (C3) * ci: run ADK path canonicalization test on hook changes * chore(release): bump to v6.5.0 * review: fix worktree prune compare-base (Critical) + extend hygiene gate to skills/ + minors - Critical: scope-lock-complete/abandon prune_jsonl compared against $ADK_ROOT but plan_abs uses $PWD -> stale lock never pruned in a worktree. Both now use $PWD (state files stay at $ADK_ROOT). Group D worktree regression test added (RED w/ bug, GREEN w/ fix). - Important: no-machine-paths.sh now scans skills/ + agents/ too (the skill rule claims enforcement); sanitized 3 pre-existing /Users/jon leaks to placeholders. - Minor: test header 12->11; lib shebang -> shellcheck shell=bash (sourced file). --------- Co-authored-by: Jon Langevin <jon@gocodealone.com>
1 parent c73786a commit ff24cf9

39 files changed

Lines changed: 962 additions & 35 deletions

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
{
1010
"name": "autodev",
1111
"description": "Autonomous development workflow skills for coding agents",
12-
"version": "6.4.0",
12+
"version": "6.5.0",
1313
"source": "./",
1414
"author": {
1515
"name": "Jon Langevin",

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "autodev",
33
"description": "Autonomous development workflow skills for coding agents: design, review, planning, execution, monitoring, and retrospectives",
4-
"version": "6.4.0",
4+
"version": "6.5.0",
55
"author": {
66
"name": "Jon Langevin",
77
"email": "jon@gocodealone.com"

.cursor-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "autodev",
33
"displayName": "Autonomous Dev Kit",
44
"description": "Autonomous development workflow skills for coding agents",
5-
"version": "6.4.0",
5+
"version": "6.5.0",
66
"author": {
77
"name": "Jon Langevin",
88
"email": "jon@gocodealone.com"

.github/workflows/path-hygiene.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: Path Hygiene
2+
on:
3+
push:
4+
pull_request:
5+
permissions:
6+
contents: read
7+
jobs:
8+
path-hygiene:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- name: No operator-home paths in committed artifacts
13+
run: bash tests/no-machine-paths.sh

.github/workflows/skill-content-check.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@ on:
55
paths:
66
- 'skills/**'
77
- 'agents/**'
8+
- 'hooks/**'
89
- 'tests/skill-content-grep.sh'
910
- 'tests/pipeline-evidence-doc-sync.sh'
1011
- 'tests/skill-cross-refs.sh'
12+
- 'tests/adk-path-canonicalization.sh'
1113
- '.github/workflows/skill-content-check.yml'
1214
pull_request:
1315
paths:
1416
- 'skills/**'
1517
- 'agents/**'
18+
- 'hooks/**'
1619
- 'tests/skill-content-grep.sh'
1720
- 'tests/pipeline-evidence-doc-sync.sh'
1821
- 'tests/skill-cross-refs.sh'
22+
- 'tests/adk-path-canonicalization.sh'
1923
- '.github/workflows/skill-content-check.yml'
2024
workflow_dispatch:
2125

@@ -29,6 +33,8 @@ jobs:
2933
- uses: actions/checkout@v4
3034
- name: Check skill content for host-specific tokens
3135
run: bash tests/skill-content-grep.sh
36+
- name: ADK path canonicalization resolver and hook wiring
37+
run: bash tests/adk-path-canonicalization.sh
3238
- name: Pipeline evidence + doc-sync contracts
3339
run: bash tests/pipeline-evidence-doc-sync.sh
3440
- name: Skill cross-references resolve

agents/team-conventions.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,11 @@ Team conventions apply identically in both execution modes:
7878
company / product-version / incident references. Dependency,
7979
runtime, and tooling version numbers are allowed when needed for
8080
accurate technical guidance.
81+
82+
## Writes: ledger
83+
84+
Every subagent's **final message** must end with a `Writes:` section — one line per file
85+
created or modified, as a **repo-relative path** (e.g. `hooks/record-activity — modified`).
86+
If any write landed outside the expected repo or worktree, flag it explicitly:
87+
`OUT-OF-TREE: <absolute path> — <reason>`. The orchestrator reads this ledger to confirm
88+
work landed where expected and to relocate or reconcile state before committing.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# ADK Path Canonicalization — Adversarial Review
2+
3+
**Phase:** design
4+
**Artifact:** `docs/plans/2026-06-03-adk-path-canonicalization-design.md`
5+
**Status:** FAIL → revised (all findings resolved in design text); re-run pending
6+
7+
## Findings (cycle 1)
8+
9+
| id | sev | class | issue | resolution |
10+
|---|---|---|---|---|
11+
| C-1 | Critical | Correctness | Resolver `cd "$(git rev-parse --git-common-dir)/.."` returns `/` (not `$cwd`) when git absent / non-git dir (empty substitution → `cd "/.."`). Reproduced: from `/tmp``/`. Violates the "degrade to today's behavior" invariant. | Resolver rewritten: capture `_gcd` first, guard `[ -n "$_gcd" ]` before the `cd`, else fall back to `$cwd`. |
12+
| C-2 | Critical | Self-referential trap | The gate scans `docs/` for a home-rooted path; the design doc + plan + retro for THIS feature must *document* that pattern, so a blanket grep fails on its own artifacts (the design originally had a literal operator-home example). | Gate regex made **placeholder-aware**: `(/Users/\|/home/)[A-Za-z0-9][A-Za-z0-9._-]*` matches a real username segment but ignores `<placeholder>` and ellipsis; author convention = illustrate with `/Users/<name>/`; plus a `path-hygiene-allow` line sentinel. All this feature's artifacts sanitized to placeholders (verified gate-clean). |
13+
| I-1 | Important | Robustness | Inline fallback `source \|\| define-fn` only fires on source *failure*; a lib that sources OK but lacks the function → exit 127 under `set -euo pipefail` kills the hook. | Replaced with post-source `declare -f autodev_repo_root >/dev/null 2>&1 \|\| autodev_repo_root(){...}` — covers missing-lib AND missing-function. |
14+
| I-2 | Important | CI wiring gap | `skill-content-check.yml` `paths:` filter is `skills/**`/`agents/**` — a docs-only/decisions-only leak PR would never trigger the gate (false guarantee). | Gate moved to a **dedicated `path-hygiene.yml`** with NO `paths:` filter → always runs on push + PR. |
15+
| I-3 | Important | Multi-component / accuracy | Retrofit list wrong by 3: `pretool-demo-fidelity-guard` MISSING (has state ref @ line 92); `posttool-pr-created` + `scope-lock-apply` listed but have NO state ref. | Replaced with the authoritative 12 from `grep -rlE 'autodev-state\|\.autodev/state' hooks/`; excluded-list documented; plan re-runs the grep as a guard. |
16+
| m-1 | Minor | Edge case | Bare repo: `--git-common-dir` returns `.` → resolver returns the bare dir's *parent* (not a fallback). | Documented in A2 as nil-impact (hooks never run in a bare repo), never hard-fails. |
17+
| m-2 | Minor | Repo precedent | Source line used `$0`; repo convention is `${BASH_SOURCE[0]:-$0}`. | Adopted `${BASH_SOURCE[0]:-$0}`. |
18+
| m-3 | Minor | Behavioral disclosure | `scope-lock-complete`/`-abandon` currently derive `repo_root` from the plan path; switching to git-canonical changes worktree behavior (intentional). | Called out explicitly in C1 as an intentional behavioral change + noted they pass `$PWD`. |
19+
| m-4 | Minor | YAGNI / honor-system | C2 ledger has no validator → degrades over time. | Acknowledged as a deliberate soft convention; orchestrator falls back to diff inspection. |
20+
21+
## Bug-class scan transcript (cycle 1)
22+
| Class | Result | Note |
23+
|---|---|---|
24+
| Assumptions | Finding (C-1, m-1) | non-git → `/` bug; bare-repo edge |
25+
| Repo-precedent | Finding (m-2) | `$0` vs `${BASH_SOURCE[0]:-$0}` |
26+
| Artifact-class precedent | Clean | adopts existing `<stem>-design-review.md` convention (v6.4.0) |
27+
| YAGNI | Finding (m-4) | C2 honor-system acknowledged |
28+
| Missing failure modes | Finding (C-1, I-1) | resolver `/` return; function-absent exit 127 |
29+
| Security | Clean | net reduction (stops machine-path leaks); env override operator-only |
30+
| Infrastructure | Finding (I-2) | CI paths-filter gap → dedicated workflow |
31+
| Multi-component | Finding (I-3) | retrofit list wrong by 3 |
32+
| Rollback | Clean | revert-merge + re-tag; no migration |
33+
| Simpler alternative | Clean | `--show-toplevel` rejected (gives worktree root); `--git-common-dir` correct |
34+
| User-intent drift | Clean | C1/C2/C3 map directly to the 3 stated pains |
35+
| Existence/runtime-validity | Finding (C-2) | self-referential gate failure on own docs |
36+
37+
## Options taken
38+
1. Single-pass git-common-dir with null guard — **taken** (C-1).
39+
2. Dedicated `path-hygiene.yml` with no `paths:` filter — **taken** (I-2).
40+
3. Placeholder-aware regex + `path-hygiene-allow` sentinel — **taken** (C-2).
41+
42+
**Verdict reasoning:** Two Criticals (resolver `/`-return + self-referential gate trap) + three Importants (incomplete fallback guard, CI paths-filter false guarantee, retrofit list wrong by 3) all had concrete low-effort fixes, now in the design text. The git primitive (`--git-common-dir`) is correct; the main repo + linked-worktree path is verified. Re-run to confirm convergence.
43+
44+
## Cycle 2 (convergence) — PASS
45+
46+
All cycle-1 findings (C-1, C-2, I-1, I-2, I-3, m-1..m-4) verified genuinely reflected in the revised design text; resolver traced correct for all 4 cwd cases with no `set -u` hazard; gate regex empirically placeholder-aware; live grep confirms exactly 12 hooks; `declare -f` safe (all 12 hooks are `#!/usr/bin/env bash`). **Converged.**
47+
48+
Two new Minors → plan-time implementation notes (not design blockers):
49+
- **scope-lock-claim dead-code:** it references `session-locks.jsonl` in a read path; retrofit should anchor the read it actually performs and not add an unused `STATE_DIR`. Plan: apply the resolver only where the file path is genuinely used.
50+
- **`local` in the lib:** `cwd`/`_gcd`/`_root` are function-global (no `local`). All consumers are bash so `local` is available; the lib will either use `local` or carry a comment that the names are intentionally global + assigned-before-read (so a future reorder can't break `set -u`). Plan decides; either is safe.
51+
52+
**Final design verdict: PASS @ cycle 2.** Proceed to writing-plans.

0 commit comments

Comments
 (0)