Skip to content

feat: full audit fixes batch - 8 commits closing 20 issues#8

Merged
George-iam merged 9 commits intomainfrom
feat/audit-fixes-batch-20260406
Apr 6, 2026
Merged

feat: full audit fixes batch - 8 commits closing 20 issues#8
George-iam merged 9 commits intomainfrom
feat/audit-fixes-batch-20260406

Conversation

@George-iam
Copy link
Copy Markdown
Contributor

Summary

Comprehensive batch of fixes and improvements from the full axme-code audit conducted on 2026-04-05/06. Addresses 20 issues found during 120-assertion E2E audit + full code review.

8 commits, each self-contained with regression verification:

  1. checkGit token-match + remove turns counter + HOME fix + legacy cleanup CLI
  2. retry classification for transient audit errors (429, timeout)
  3. bash file tracking via transcript parser + hasActivity fix
  4. oracle rescan triggers - deterministic + LLM
  5. worklog lifecycle events - session_start + check_result
  6. decision supersede mechanism + status field + newer-wins rule
  7. ghost session detection + path normalization + cliPath guard
  8. remove dead code report.ts

Issues closed

ID Issue Commit
B1 checkGit protectedBranch substring false positive c25e476
G1 AUDIT_PROMPT ORACLE_CHANGES trigger missing ba8f356
G2 PostToolUse not tracking Bash file mutations af6763f
G3 MAX_AUDIT_ATTEMPTS not distinguishing retryable errors 59b6b16
G4 session_start worklog event dead code 8f1036b
G5 check_result worklog event dead code 8f1036b
G6 turns counter always 0, misleading c25e476
N1 hasActivity bypass losing filesChanged af6763f
N2 process.env.HOME undefined on Windows/containers c25e476
N3 report.ts full dead code ea58741
N20 audit-spawner cliPath undefined guard 9efd2ab
A1 No supersede/revoke for decisions 29c7a63
A4 Ghost session auto-detection 9efd2ab
E1 pending-audits rmdir EISDIR c25e476
E3 bumpTurn multi-window misattribution (removed) c25e476
E6 filesChanged path normalization 9efd2ab
L1 31 pre-PR#7 sessions without origin c25e476 (cleanup CLI)
L2 19 pre-PR#7 audit logs without resume c25e476 (cleanup CLI)
L3 b1cf9e64 inconsistent meta state c25e476 (cleanup CLI)

New CLI commands

  • axme-code cleanup legacy-artifacts [--dry-run] - removes pre-PR#7 sessions/logs with backup
  • axme-code cleanup decisions-normalize [--dry-run] - adds status:active to all 2444 decisions

New capabilities

  • Decision lifecycle: active/superseded/deprecated/revoked status + supersedeDecision/revokeDecision API
  • Newer-wins rule: conflicting decisions resolved by date, surfaced in agent context
  • Bash file tracking: extractBashWritePaths parses redirects/sed/cp/mv/rm/tee/curl from transcript
  • Oracle rescan: deterministic trigger on structural file changes (package.json, CLAUDE.md, etc.)
  • Retry classification: 429/timeout errors auto-retry up to 5x via stale-pending mechanism

Test plan

  • PR#7 regression: 17/17 PASS
  • Full storage audit: 119/119 PASS
  • Real LLM smoke test: 24/24 PASS (detached worker, $0.044)
  • Cleanup legacy-artifacts dry-run: 31+19+1 (matches expected)
  • Cleanup decisions-normalize dry-run: 2444 files, 57 locations
  • Real workspace read: 56 repos, all parse correctly

…cleanup CLI

- checkGit protectedBranch: token-level matching instead of substring
  (git push origin main-file-feat was falsely blocked)
- Remove turns counter: bumpTurn/incrementTurns removed from SessionMeta,
  server.ts, session-cleanup — counter was 0 in 96% of sessions, misleading
- safety.ts: use os.homedir() instead of process.env.HOME for ~ expansion
  (fixes undefined on Windows/containers where HOME is unset)
- pending-audits rmdir: use rmSync instead of unlinkSync (EISDIR fix)
- New CLI command: axme-code cleanup legacy-artifacts [--dry-run]
  removes pre-PR#7 sessions (no origin), audit logs (no resume), legacy dirs
  with backup to .axme-code/backups/

Closes: B1, G6, L1, L2, L3, E1, E3, N2 from full audit plan.
recordAuditFailure now distinguishes retryable errors (429, rate limit,
ETIMEDOUT, ECONNRESET, etc.) from deterministic failures (prompt too long,
parser errors). Retryable errors leave session in stale-pending state so
orphan scan retries on next MCP startup. RETRYABLE_MAX_ATTEMPTS=5 caps
infinite retries. Non-retryable errors immediately mark session as failed.

This fixes the issue where 3 sessions today needed manual auditAttempts
reset after transient Anthropic 429 errors.

Closes: G3 from full audit plan.
- hasActivity now includes filesChanged.length > 0 as a trigger
  (fixes N1: audit was skipped when transcript empty but files changed)
- parseTranscriptFromOffset collects raw bash commands in bashCommands[]
- New extractBashWritePaths utility parses redirects, sed -i, cp, mv,
  rm, touch, tee, curl -o, wget -O from shell commands
- session-cleanup supplements filesChanged from bash commands before audit
- parseAndRenderTranscripts aggregates allBashCommands across refs

Closes: G2, N1 from full audit plan.
- Deterministic pre-check: if filesChanged contains structural manifests
  (package.json, pyproject.toml, go.mod, CLAUDE.md, etc.) oracle rescan
  fires automatically without waiting for LLM verdict
- AUDIT_PROMPT updated with explicit ORACLE_CHANGES instructions: lists
  what counts as YES (new dependencies, version upgrades, new dirs,
  CLAUDE.md changes) vs NO (regular edits, bug fixes, refactoring)
- Both triggers feed into existing runOracleScan code path

Closes: G1 from full audit plan.
- logSessionStart called in ensureAxmeSessionForClaude on fresh session
  creation (fires once per AXME session on first hook call)
- logCheckResult called after audit in session-cleanup (PASS/FAIL with
  extraction counts: "3 mem, 5 dec, 1 safety")
- Both were dead exports in worklog.ts, now active

Closes: G4, G5 from full audit plan.
Decision lifecycle: active -> superseded/deprecated/revoked.

- Decision type: +status, +supersededBy, +supersedes, +revokedAt, +revokedReason
- listDecisions() defaults to active-only (undefined = active for backward compat)
- supersedeDecision(path, oldId, newInput): marks old as superseded, creates new
- revokeDecision(path, id, reason): marks as revoked with timestamp
- formatDecisionFile/parseDecisionFile: handle all new fields in frontmatter
- decisionsContext: includes (date) per decision + "newer wins" rule header
- MCP server instructions: DECISION CONFLICT RULE added
- CLI: axme-code cleanup decisions-normalize [--dry-run] adds status:active
  to all 2444 existing decisions across 57 workspace locations

Closes: A1 from full audit plan.
- Ghost sessions (<2s lifetime, 0 files) auto-marked as done without LLM
  audit (saves cost on Bug F artifacts and race condition empties)
- trackFileChanged normalizes paths via path.resolve before dedup
  (fixes /home/user/./x.ts vs /home/user/x.ts producing duplicates)
- audit-spawner guards against undefined process.argv[1]

Closes: A4, E6, N20 from full audit plan.
src/storage/report.ts had 5 exports (appendReport, readReport,
saveArtifact, formatAgentHeader, formatTokens) with zero imports
anywhere in the codebase. Removing to reduce maintenance surface.

Closes: N3 from full audit plan.
Denied prefix `git push origin main` was incorrectly blocking
`git push origin main-file-feat` via simple string startsWith.
Added isPrefixBoundaryMatch: when prefix ends with alphanumeric,
next char must be a word boundary (space, end, etc.), not a
continuation like hyphen. Path prefixes like `rm -rf /` still
match `rm -rf /etc` correctly since `/` is non-alphanumeric.

12/12 test cases pass (7 blocked, 5 allowed).
@George-iam George-iam merged commit 73349b3 into main Apr 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant