feat(audit-feature-flags): rebuild as a doctor (wizard native) - #329
feat(audit-feature-flags): rebuild as a doctor (wizard native)#329ryanwaits wants to merge 7 commits into
Conversation
|
Specific areas, if you're offering: mostly trade-offs I made deliberately but am not totally certain about yet: 1. Speed vs. depth. The old audit was static-only and quick. This one also probes 2. Rebuilding in place vs. a new skill. I kept the id, command, and 3. Check calibration. Severities are my judgment, and across runs I saw one borderline check flip between 4. Prompt weight. More checks means a longer skill. It's comfortable on a small app but I haven't run it against a large monorepo... |
edwinyjlim
left a comment
There was a problem hiding this comment.
overall, this is a solid list. the checks.md file is a little unwieldy though. i'd imagine it's going to be hard to scale prompts inline like that, but i like the task <> subagent structure
| ## Available tools | ||
|
|
||
| {{> mcp-tool-calling}} | ||
|
|
||
| **Verify (read-only):** | ||
| - `Glob` / `Grep` / `Read` — static checks over the source tree. | ||
| - `Bash` (plain `curl` only) — live `/flags` probes. Keep probe commands minimal and legible; see `references/checks.md` for the exact shapes. | ||
| - `feature-flag-get-all` (or the equivalent MCP flag-listing tool; `execute-sql` fallback) — the project's flag roster. | ||
| - `mcp__wizard-tools__check_env_keys` — which env keys exist (never reveals values). | ||
| - `docs-search` — latest doc URLs for remediation links. |
| references: | ||
| preamble: "**Read ONLY this file.** Do not read any other reference file until this one tells you to." |
There was a problem hiding this comment.
FYI this is a prompt guardrail for the agent to follow the references in a strict sequence. I know you've defined the flow in the description.md but sometimes agent ignores instructions
There was a problem hiding this comment.
ok thats fair, good catch - ive restored as prose guardrails
| ## Doc links per check | ||
|
|
||
| - `ff-bootstrap-when-known-set`, `ff-bootstrap-distinct-id-mismatch` → https://posthog.com/docs/feature-flags/bootstrapping | ||
| - `ff-await-readiness`, `ff-default-values`, `ff-identified-only-pre-auth-targeting`, `ff-eval-before-identify` → https://posthog.com/docs/feature-flags/best-practices | ||
| - `ff-key-authenticates`, `ff-flags-endpoint`, `delivered-*`, `ghost-*` → https://posthog.com/docs/feature-flags/troubleshooting | ||
| - `ff-evaluated-not-reported` → https://posthog.com/docs/experiments/exposures | ||
| - `stale-*`, `ff-active-but-unreferenced` → https://posthog.com/docs/feature-flags/cleaning-up-stale-flags | ||
| - `ff-local-eval-polling-interval`, `ff-local-eval-in-edge-handlers` → https://posthog.com/docs/feature-flags/local-evaluation | ||
| - `ff-test-ci-gating` → https://posthog.com/docs/feature-flags/cutting-costs |
There was a problem hiding this comment.
ooh mapping tasks to docs is interesting
|
Some discussions based on what you raised. Feel free to discuss but defer execution if you have ideas. I again don't expect any of this to happen during this short superday:
And if, say, we can't make it faster, what would you optimize for? speed vs. depth? how would you make this decision or run an experiment.
|
sarahxsanders
left a comment
There was a problem hiding this comment.
this is a big step up from what it replaced, well done!! some high level stuff:
- going from grep the source to actually probing flags is great
- some contradictions in the context that need some cleaning up, I'd be curious to see how many turns the agent wastes when it gets tripped up by one!
|
|
||
| ## Part 1 — Static checks (parallel subagents) | ||
|
|
||
| Emit `[STATUS] Auditing feature flag correctness`, then make **six `Agent` tool calls in a single message** for the correctness checks (Tasks A–E and Task I). When all five return, emit `[STATUS] Auditing feature flag cost optimization` and dispatch the cost checks (Tasks F–H) the same way — one `Agent` call per check that actually runs, in a single message. Two cost checks are gated on the pre-flight local-evaluation signal; for a gated check that is skipping, emit its `audit_resolve_checks` update directly (`status: "pass"`, `details: "skip: local evaluation not detected"`) instead of dispatching a subagent. |
There was a problem hiding this comment.
this contradicts a little, "six agent tool calls" - "When five return", looks like it's left over from the old version possibly, but I'd clean this up because I could see the agent tripping on this and wasting turns
There was a problem hiding this comment.
yep, it was six after all - good catch again. i also also relettered to kill the task/check collision
|
|
||
| ### Check N — `ff-stale-rolled-out` (sweep) | ||
|
|
||
| What it verifies: flags at **100% rollout with no conditions** that are still gated in code — the check is equivalent to a hardcoded value: dead branches, needless evaluations, cleanup candidates. (The tenant-side twin, zero-reference active flags, is Task I in Part 1 — `ff-active-but-unreferenced`.) |
There was a problem hiding this comment.
I think there's some stuff here that needs cleaned up, is left over from the old version or maybe edits you did! you mention the wrong task and check
also side note: this is a superrrrrr long file, I wonder if the agent is a little slow based on the file side and sheer amount of context here?
|
@gewenyu99 on speed vs depth: i think i'd optimize for speed, because depth is something you can ask for specifically later. the checks already group into areas, so on separate vs all doctors: separate commands, same content, mostly so we don't end up with two copies of the check wording quietly drifting apart |
Problem
Following up on the flags-doctor thread:
audit feature-flagsis static and read-only today: greps the source, reads the roster, hands back a report. It never checks whether flags reach the running app, and can't act on what it finds. Its own report template signs off with "runtime assumptions unproven by the static code."So a typo'd flag key returns
undefinedforever with no error, and since the audit only compares tenant→code, it can't see it. On a test app with one planted, the current skill told me to "confirm that every active flag matches one of the four keys referenced in code:beta-serach, …" — i.e. validate the typo as truth.Changes
Rebuilt as a doctor: verify (read-only) → one
wizard_askmulti-select → apply only what's selected. Shaped afterweb-analytics's doctor per Edwin's suggestion. Skill id,cli:block, and command unchanged. All nine static checks kept.New:
/flagswith the project's key via the app's configured host, cross-checks the roster, surfaces per-flagreasoncodes.$feature_flag_calledsuppression, config-level and per-call.The interlock, from Vincent's "evaluating ≠ sending events" point: staleness is measured from
$feature_flag_called, so a heavily-used flag with suppressed events looks unused — archive it and you turn off a live feature. The doctor withholds all tenant-side cleanup until reporting is verified, and explains why.Bot filtering of
/flagsis expected behavior, so it's a teaching note rather than a finding — and probes send a browser-like UA so we don't false-alarm on it.Test plan
npm test(140) andnpm run buildgreen; zip builds, warlock clean,cliEntriesunchanged.--local-mcp+ the wizard PR): all three caught with the right severities, two selected fixes applied surgically, archive candidate withheld by the interlock, healthy flags verified delivered.