Commit Graph
18 Commits
Author SHA1 Message Date
Paul BakausandGitHub e46e0da885 Centralize critique snapshot reading (#511)
Make critique storage the single owner of snapshot discovery and frontmatter parsing, and keep context signals focused on summarizing the canonical result.

AI-assisted: Prepared by Codex under pbakaus's scheduled architecture-refactor authorization.
2026-08-05 15:27:02 -07:00
Paul BakausandClaude Code 01d5d357c5 The develop candidate leads with an advertised develop default rev
Round eight closes the stale-local class completely: the develop
candidate sits before the remote-default entries, so when origin/HEAD
itself points at develop, its name claim let a stale local develop win
over the fresher origin/develop. The candidate now leads with any
remote-advertised develop rev, exactly as the remote-default and
upstream candidates already lead with theirs. main/master were already
covered since their remote-default entries come first in the order.
Failing-first test forces local develop two commits behind.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-26 19:04:48 -07:00
Paul BakausandClaude Code e2c1c43ee7 Remote defaults lead with their own rev, like upstreams already do
Round seven: a remote-advertised default candidate tried the local
branch first, so a stale local main outranked the fresher origin/main
the symref points at and refilled changedFiles with the divergence.
The candidate now leads with the advertised remote rev, mirroring the
upstream candidate's reasoning. Failing-first test: local main forced
two commits behind the remote default, feature delta stays clean.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-26 18:56:33 -07:00
Paul BakausandClaude Code a470fc777a Read the upstream as a full symbolic ref instead of guessing at prefixes
Round six, and the upstream-parsing ambiguity dies at the root: @{u} is
now resolved via rev-parse --symbolic-full-name, where refs/heads/...
IS a local upstream and refs/remotes/<r>/... IS remote-tracking. The
previous remote-membership heuristic still misread a local feature/foo
upstream when a remote literally named "feature" existed. The
adversarial test now configures exactly that remote and passes.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-26 18:48:14 -07:00
Paul BakausandClaude Code f89b6c10b1 Only strip a remote prefix that names a configured remote
Round-five bot findings, one real root cause: splitRemoteRef treated the
first slash in any ref as a remote separator. A local upstream named
release/2.0 was truncated to "2.0", and feature/foo tracking from branch
foo collapsed to the current branch's own name and was self-skipped,
discarding a valid base both times.

The split now happens only when the prefix names a configured remote;
otherwise the whole ref is one local branch name. The per-remote HEAD
symref loop strips its own queried prefix directly (that remote may be
fabricated in tests or partial clones without appearing in git remote).
The reported pruned-upstream shape already resolves via the multi-remote
rev lists from the previous round; its test now guards that.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-26 18:39:20 -07:00
Paul BakausandClaude Code 386d3e7051 Cover every remote in each candidate's rev list
Cursor and Greptile converged on one root cause from the previous round:
candidate revs stopped at origin (develop tried only develop and
origin/develop; a remote-default entry carried only its own rev), so the
name-level dedup discarded a same-name base living on another remote. A
fork-parent layout with develop only as upstream/develop, or a pruned
origin/main beside a live upstream/main, lost its base entirely.

revsFor(name) now expands to the local branch plus <remote>/<name> for
every remote (origin first), and all named candidates use it, which is
exactly what makes the dedup safe. Two failing-first tests cover the
upstream-only develop and the pruned-origin/live-upstream main shapes.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-26 18:23:56 -07:00
Paul BakausandClaude Code 46f29ca8b3 Guard detached HEADs and non-origin remote defaults
Two more real gaps from the post-rebase review round: a detached
checkout reads its branch as the literal HEAD, so the integration guard
never fired and candidate selection could diff a detached tip on main
against develop; and the remote-default check only consulted origin, so
a fork-parent layout whose only remote is upstream lost the guard on
its default branch entirely.

The guard now treats a detached HEAD as no-diff-base, and default-branch
symrefs are collected from every remote (origin first), feeding both the
guard and the candidate list. Two failing-first tests cover a detached
tip beside a diverged develop and an upstream-only trunk default.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-26 18:14:34 -07:00
Paul BakausandClaude Code afb5d9a479 Guard non-standard default branches like conventional ones
Cursor Bugbot: sitting on a non-standard default such as trunk (the
origin/HEAD target) still ran candidate selection, where develop or main
could win and produce an integration-vs-integration diff. The guard now
treats the remote default branch as an integration branch alongside the
conventional names. Failing-first test: on trunk with a develop branch
present, the scope stays the working tree.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-25 20:17:55 -07:00
Paul BakausandClaude Code e82653965c An existing develop outranks a main-pointing origin/HEAD
Cursor Bugbot's remaining round-1 finding held for the current code
too: in a git-flow repo whose platform default was never flipped off
main, a feature branch without an upstream picked origin/HEAD's main
over the develop branch features actually merge to, dragging the
develop-vs-main divergence into scan targets. develop now sits between
the upstream signal and origin/HEAD in the candidate order; repos
without a develop branch are unaffected. Failing-first test covers the
exact shape (develop exists, origin/HEAD -> main).

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-25 20:17:55 -07:00
Paul BakausandClaude Code b9d294b29c Close the integration-branch guard bypass; accept local upstreams
Cursor Bugbot round two, both real: an upstream or origin/HEAD naming a
DIFFERENT integration branch bypassed the conventional-name guard, so
sitting on develop with the remote default at main still produced the
integration-vs-integration divergence this detection exists to prevent.
And splitRemoteRef returned null for a slashless @{u}, silently dropping
local upstreams (branch.<x>.remote = ".").

Base detection is now skipped entirely on an integration branch: no
signal may override the working-tree scope there. A slashless upstream
resolves as its own name and rev. Two failing-first tests: origin/HEAD
pointing at main while sitting on develop, and a feature branch
tracking a local canary branch.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-25 20:17:55 -07:00
Paul BakausandClaude Code ea098ceb96 Accept remote refs as diff bases; honor non-origin upstreams
Both review bots found real gaps in the first pass: candidates were
verified as local branch names only, so an origin/HEAD target with no
local checkout fell through, and stripOrigin() dropped upstreams on any
remote not named origin (fork workflows tracking upstream/release).

Candidates now carry a display name plus the revs to try in order: the
upstream's remote rev wins outright (it tracks the actual merge target,
so it beats a possibly stale local branch of the same name), origin/HEAD
tries the local branch then the remote-tracking ref, and the
conventional names each try local then origin/<name>. git.base keeps
reporting the friendly branch name while the diff runs against whichever
rev resolved. Two new failing-first tests: remote-only default branch,
and an upstream on a remote named upstream with no local base branch.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-25 20:17:55 -07:00
Paul BakausandClaude Code a50702f2b6 Detect the diff base instead of assuming main/master
context-signals hardcoded ['main', 'master'] as diff-base candidates, so
repos integrating through develop (or any other branch) diffed against
the wrong base: git.changedFiles carried the entire divergence and
downstream commands scanned the wrong set (issue #302).

The base is now detected, most specific signal first: the branch's
configured upstream (@{u}; a branch pushed with -u tracks itself and is
skipped by the self-check), then the remote's default-branch symref
(origin/HEAD), then the conventional integration names including
develop. The conventional fallbacks are withheld when the current branch
is itself one of them, so sitting on main in a repo that also has
develop keeps the working-tree scope instead of diffing two integration
branches against each other.

Five tests (three failing-first): develop-based feature branch,
origin/HEAD detection with a non-standard default name, upstream
tracking, on-the-integration-branch fallback, and the
integration-vs-integration guard.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-25 20:17:55 -07:00
Paul BakausandClaude Code a1a6441ba1 Exempt hidden dirs that conventionally hold UI source from the skip rule
Greptile's review correctly flagged a regression in the blanket
hidden-dir skip: .vitepress/theme/*.vue and .storybook/ preview files are
real UI source that the walker scanned before this branch. Both the
walker and the scan-target filter now carry a two-entry allowlist
(HIDDEN_SOURCE_DIRS) for those conventional locations; every other
hidden dir keeps being skipped.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-25 18:04:55 -07:00
Paul BakausandClaude Code 9f008ebf82 Skip hidden dirs in the detector walker and vendored paths in scan targets
When impeccable (or any agent tool) is installed into a project's
.claude/.cursor/.codex tree, a root scan descended into the vendored skill
code and reported the detector's own example strings as findings, and
context-signals returned installed-skill files as scan candidates whenever
the harness tree appeared in the branch diff (issue #303).

Rather than growing SKIP_DIRS by a denylist of harness names that drifts
as new tools appear, the walker now skips every hidden directory during
recursion — which already covered .git/.next/.nuxt/.svelte-kit/.turbo/
.vercel, and covers all present and future harness installs plus
.impeccable itself. SKIP_DIRS shrinks to the four non-hidden entries.
An explicitly passed hidden target still scans: only child entries are
name-checked, never the root the walker is given.

scanTargets() applies the same rule to git-changed files (directory
segments only, so root dotfiles keep their existing behavior), and falls
through to source-dir targeting when the only dirty files are vendored.

Prepared with AI assistance (Claude Code), directed by @pbakaus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-07-25 17:51:12 -07:00
Paul Bakaus bbed6eef08 Refresh the Impeccable product experience
Rework the landing page proof, steering demo, feature grid, slop catalog, detector coverage, theming, Live workflow, and responsive behavior.\n\nAI-assisted implementation by OpenAI Codex.
2026-07-15 23:29:47 -07:00
Paul BakausandClaude Opus 4.8 0047981a95 fix(skill): target local files for detect, never a URL (#159)
Rework context-signals' detect target after review: a URL meant a costly
Puppeteer render (and a probed port might not even be this project), and the
index.html-or-bail fallback failed most real apps (no root index.html).

New priority: (1) the scannable markup/style files in the dirty git tree
(what the user is working on, small and local); (2) a local source dir
(src / app / components / pages / public — the detector walks these and skips
node_modules / dist / build); (3) a root index.html, else the project root as
a last resort when there's code. Emits `scan.targets` (a list) + `scan.via`.
Never a URL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 15:50:53 -07:00
Paul BakausandClaude Opus 4.8 772aa73aa3 feat(skill): make bare /impeccable context-aware (re: #159)
Reshape of the "/impeccable suggest" proposal in #159. Instead of adding a
24th command (menu pollution + the command-add tax + its own discoverability
problem), upgrade the path users already hit: bare `/impeccable` with no
argument.

- New skill/scripts/context-signals.mjs gathers cheap, deterministic signals
  (setup gaps, register, latest cached critique score, git change scope, a
  dev-server port probe, and a `scan.detectTarget` for the detector) and emits
  JSON. It does NOT score or rank, and it does NOT run the detector itself
  (the engine isn't importable in an installed skill, and shelling npx+jsdom
  would risk a hang) — the agent reasons over the raw signals.
- SKILL.md routing rule 1 now leads with the 2-3 highest-value next commands,
  each with a reason from the signals, then the full menu. Never auto-runs;
  always confirms. Reuses init's "Recommend starting points" vocabulary. When
  a project has never been critiqued it offers critique; when scan.detectTarget
  is set it runs `npx impeccable detect --fast --json` and folds the hits in.
- Export extractRegister from context.mjs for reuse.

Stays 23 commands; no metadata/pin/site-data changes. Unit-tested, including a
regression guard for porcelain leading-space path parsing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 15:50:53 -07:00
Paul BakausandClaude Opus 4.8 5793e84292 feat(skill): make bare /impeccable context-aware (re: #159)
Reshape of the "/impeccable suggest" proposal in #159. Instead of adding a
24th command (menu pollution + the command-add tax + its own discoverability
problem), upgrade the path users already hit: bare `/impeccable` with no
argument.

- New skill/scripts/context-signals.mjs gathers cheap, deterministic signals
  (setup gaps, register, latest cached critique score, git change scope, a
  dev-server port probe) and emits JSON. It does NOT score or rank — no
  brittle weights table — the agent reasons over the raw signals.
- SKILL.md routing rule 1 now leads with the 2-3 highest-value next commands,
  each with a reason from the signals, then the full menu. Never auto-runs;
  always confirms. Reuses init's "Recommend starting points" vocabulary.
- Export extractRegister from context.mjs for reuse.

Stays 23 commands; no metadata/pin/site-data changes. Unit-tested, including
a regression guard for porcelain leading-space path parsing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 15:21:06 -07:00