# Click Path Audit Edho Ferdian

> >-

- **Type:** Skill
- **Install:** `agentstack add skill-edhoferdian-eef-click-path-audit-edho-ferdian`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [edhoferdian](https://agentstack.voostack.com/s/edhoferdian)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [edhoferdian](https://github.com/edhoferdian)
- **Source:** https://github.com/edhoferdian/EEF/tree/main/.hermes/skills/click-path-audit-edho-ferdian

## Install

```sh
agentstack add skill-edhoferdian-eef-click-path-audit-edho-ferdian
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Click-Path Audit — Edho Ferdian Mode

Ordinary debugging asks: does the handler exist, does it crash, are the types
right. All three can be YES while the button is still broken. This skill asks
the question those three miss:

> **Does the final state match what the control's label promises?**

## The defect class

A "New Email" button called `setComposeMode(true)` and then
`selectThread(null)`. Both functions existed, neither threw, types were
correct — and `selectThread` reset `composeMode: false` as an undeclared side
effect. The button did nothing. A systematic debugging pass that found 54 other
defects missed this one, because nothing about it is visible from either
function in isolation. It only appears when you look at the *sequence*.

## Scope first

This audit is expensive; scope it before starting:

| Scope | When |
|-------|------|
| One control | A user reported one specific broken button |
| One screen | A new page was just built, or one screen misbehaves |
| One store | A shared store action was modified — audit every caller of the changed actions |
| Whole app | Pre-release, or after a refactor that touched shared state broadly |

For a whole-app audit, Step 1 must complete before any Step 2 work begins —
its output is the input for everything else. On a harness with sub-agent
delegation, build the map yourself, then fan out Step 2 to
`click-path-tracer-edho-ferdian` **in parallel** — one delegate per
screen/module, each given the complete map, never building its own
partial one. This is worth the delegation overhead at whole-app scale
(potentially dozens of touchpoints, each independent to trace once the
map exists) but not for the smaller scopes above — trace those inline.
On a harness with no delegation primitive, trace every touchpoint inline
regardless of scope, per Step 2 below.

## Step 1 — Build the side-effect map (mandatory, always first)

For every state store in scope (Zustand store, Redux slice, React context
reducer, signal container, view model), record for each action:

- which fields it **sets**
- which fields it **resets** as a side effect — fields it does not conceptually
  own

```
STORE: emailStore
  setComposeMode(bool)  → sets {composeMode}
  selectThread(t|null)  → sets {selectedThread, selectedThreadId, messages, drafts}
                          RESETS {composeMode: false, composeData: null, redraftOpen: false}
  setDraftGenerating(b) → sets {draftGenerating}

DANGEROUS RESETS (an action clearing state it does not own):
  selectThread → resets composeMode (owned by setComposeMode)
  reset        → resets everything
```

The DANGEROUS RESETS list is the whole point of this step. Every defect this
skill exists to catch lives there. Do not proceed to Step 2 with an incomplete
map — an audit against a partial map produces false confidence, which is worse
than no audit.

## Step 2 — Trace each touchpoint

For every interactive element in scope (`onClick`, `onSubmit`, `onChange`,
keyboard handler, gesture handler):

```
TOUCHPOINT: "New Email" — ThreadList.tsx:88
  HANDLER: onClick
    1. setComposeMode(true)   → sets {composeMode: true}
    2. selectThread(null)     → RESETS {composeMode: false}   ← CONFLICT
  EXPECTED (from the label): a blank compose form opens
  ACTUAL: composeMode is false; nothing renders
  VERDICT: BUG — Sequential Undo
```

Check every trace against these six patterns:

1. **Sequential undo** — a later call resets what an earlier call set. The
   canonical case above.
2. **Async race** — two async calls both write the same field; the final value
   depends on resolution order, not on intent.
3. **Stale closure** — a memoized handler captures an old value, so two
   increments apply the same stale base and the effect happens once, not twice.
4. **Missing transition** — the handler validates, logs, or sets a flag but
   never performs the action the label promises (no API call, no navigation,
   no persistence).
5. **Conditional dead path** — the real work sits behind a condition that is
   always false at that point in the lifecycle.
6. **Effect interference** — the handler sets a field and a watcher/effect
   observing that field immediately resets it.

For each call in a trace, answer four questions: what does it read, what does
it write, does it touch shared state, and does it reset anything as a side
effect.

## Step 3 — Report

```
CLICK-PATH-001 [HIGH]
  Touchpoint: "New Email" — src/components/ThreadList.tsx:88
  Pattern:    Sequential Undo
  Trace:
    1. setComposeMode(true) → sets {composeMode: true}
    2. selectThread(null)   → RESETS {composeMode: false}
  Expected: blank compose form opens
  Actual:   nothing renders; composeMode is false by the end of the handler
  Fix:      reorder (selectThread first, then setComposeMode), or remove the
            undeclared composeMode reset from selectThread and clear it at the
            call sites that actually mean to
```

Severity: **CRITICAL** — a money, auth, or destructive control that silently
does nothing (the user believes the action happened). **HIGH** — a primary
control that does nothing. **MEDIUM** — a control whose final state is partly
wrong. **LOW** — a redundant call with no user-visible effect (dead code, not a
defect).

## Boundaries — what this is not for

- API-level defects (wrong response shape, missing endpoint) — a click-path
  trace ends at the request; take those to normal debugging, and to
  `test-authoring-edho-ferdian/references/regression-testing.md` for the test.
- Styling and layout — visual inspection, or a QA sweep
  (`e2e-testing-edho-ferdian/references/qa-sweep.md`).
- Performance — `performance-audit-edho-ferdian`.

## Handoff — every finding earns a test

A click-path finding is a proven defect with a known reproduction, which makes
it the ideal RED gate. Hand each one to `dev-kickoff-edho-ferdian`'s normal
PLAN → TEST → IMPLEMENT loop: the failing test asserts the *final* state after
the handler runs, not that each individual function was called. A test that
asserts `setComposeMode` was called would have passed against the original bug.

## Language routing (fixed — see skill-authoring-edho-ferdian's canonical contract)

Communication to the user in Bahasa Indonesia; the trace report and call
sequence in English, since it gets pasted into an issue or handed to
`dev-kickoff-edho-ferdian`'s TEST/IMPLEMENT loop. Full contract:
`skill-authoring-edho-ferdian` §7.

## Global rules

1. **Store map before traces, always.** No exceptions; a partial map hides the
   exact defect this skill targets.
2. **Trace in execution order.** The order is the evidence.
3. **Judge against the label, not against the code.** The label is the
   contract with the user.
4. **A finding is a trace, not an opinion.** Every report shows the numbered
   call sequence with the conflicting write marked.
5. **Do not fix inside the audit.** Report, then hand off — an audit that
   starts editing loses its own coverage.

## Growth path

This skill is intentionally single-file. If the defect-pattern list (Step 2)
grows past six patterns, or this file passes ~250-300 lines, split framework-
specific tracing detail (e.g. a Zustand/Redux-specific vs. a signals-specific
lens) into `references/`, following the domain+lens pattern other skills in
this ecosystem use — do not let a single growing file replace that split.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [edhoferdian](https://github.com/edhoferdian)
- **Source:** [edhoferdian/EEF](https://github.com/edhoferdian/EEF)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-edhoferdian-eef-click-path-audit-edho-ferdian
- Seller: https://agentstack.voostack.com/s/edhoferdian
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
