Skip to content

Three-stage scan pipeline + expression-as-authored-contract#68

Merged
nahiyankhan merged 27 commits intomainfrom
agent-generation
May 5, 2026
Merged

Three-stage scan pipeline + expression-as-authored-contract#68
nahiyankhan merged 27 commits intomainfrom
agent-generation

Conversation

@nahiyankhan
Copy link
Copy Markdown
Collaborator

@nahiyankhan nahiyankhan commented Apr 30, 2026

Summary

This branch reshapes Ghost from a single-package fingerprint tool into a four-tool topology around a three-stage scan pipeline, then iterates the expression.md contract until it's an authored-only artifact agents can write, lint, and govern without parallel binary state.

Topology

  • Decompose ghost-drift into @ghost/core (workspace-only library: embedding math, target resolver, skill loader, shared schemas) plus four tools: ghost-expression (scan + authoring), ghost-drift (drift detection + governance), ghost-fleet (cross-project elevation), and ghost-ui (reference design system to dogfood against).
  • Authoring verbs (lint, describe, diff, emit review-command, emit context-bundle) move from ghost-drift to ghost-expression. Stub commands stay registered in ghost-drift for one major-version cycle.
  • ghost-map is folded back into ghost-expression; its inventory verb and topology recipe live there now.

Three-stage scan pipeline

A scan is now map.md (topology, stage 1) → survey.json (observed evidence, stage 2) → expression.md (authored interpretation, stage 3). All three stages and their skill recipes (map.md, survey.md, profile.md, plus the scan.md orchestrator) ship in ghost-expression. The bucket → survey rename happens partway through the branch — search for survey in the resulting tree.

Schemas: ghost.map/v2 + ghost.survey/v2

  • ghost.map/v2 requires implemented_surfaces[] evidence so the profiler is grounded in real screens, not hypothetical ones. Source-graph scans let one primary subject supply usage/salience while resolver sources supply concrete values.
  • ghost.survey/v2 catalogues every concrete design value (palette, spacing, typography, radii, shadows, breakpoints, motion, layout primitives) plus tokens, components, and UI surfaces — each row content-hashed for deterministic ID. survey.libraries[] is gone (icon/primitive choices aren't part of the design language; load-bearing library calls surface as prose evidence in the profile stage). Survey recipe now requires a Tailwind class-atom pass so utility-driven repos don't undercount their scale.

expression.md schema iterations on this branch

The contract gets simpler over the course of the branch. End state: YAML frontmatter (machine layer — references, palette/spacing/typography/surfaces, checks[]) + a three-section prose body (# Character# Signature# Decisions).

  • Restored # Signature as the final-picture guidance section and added direct references for living specs/components/examples.
  • Added checks[] as the v0 authoring surface for drift review — human-promoted, grep-friendly review gates with pattern, paths, contexts, observed_count, and presence_floor for codifying absences.
  • Added a perceptual-weight prior (@ghost/core) that calibrates emitted check severity — color and font-family are loud, shape and elevation structural, spacing and motion-detail rhythmic. Promoted checks render as a Rams-shaped review slash command grouped by Critical / Serious / Nit.
  • Added a canonical decision-dimension vocabulary (12 slugs: color-strategy, surface-hierarchy, shape-language, typography-voice, spatial-system, density, motion, elevation, theming-architecture, interactive-patterns, token-architecture, font-sourcing) so cross-project aggregation can group decisions. Novel slugs may pair with an optional dimension_kind mapping to a canonical survey.
  • Removed roles[] — slot bindings either fall out of decisions or live in survey.json components[].
  • Removed based_on rule provenance, distinctiveTraits, and the signature body section (then a different # Signature was reintroduced — see above; not the original distinctive-traits-laden section).
  • Removed on-disk embedding and the decision-fragment surface. Embeddings are recomputed at load time from the authored body. expression.md is now an authored-only contract — no parallel binary state, nothing to keep in sync.

New CLI surface

  • ghost-expression verify-profile <expression> <survey> — fidelity gate after profiling. Palette values must be survey-backed; promoted checks must be calibrated against survey/root.
  • ghost-expression survey summarize — bounded profile digest (compact / standard / full budgets) so the profiler can ground itself without loading the full survey into context.
  • ghost-expression survey catalog — derived value enum/spec view of a survey.
  • ghost-expression scan-status [dir] — report which stages have produced artifacts and what to run next.
  • ghost-expression inventory [path] — emit raw repo signals for the topology recipe (migrated from ghost-map).
  • ghost-expression lint auto-detects file kind by extension/content (expression.md, map.md, survey.json).

Other

  • One-liner curl installer (install/install.sh) so the skill bundle installs without npm or a build step; recipes carry prose fallbacks for the most-called CLI verbs.
  • Reframed skill-bundle copy to lead with the agent and drift, not the deterministic CLI.
  • Composition-pattern steering so generated expressions and context bundles distinguish article/tracker/comparison/card output shapes.
  • INVARIANTS.md folded into CLAUDE.md and .github/workflows/ghost-ci.yml removed (CI lives in lefthook + per-package).
  • Dogfooded end-to-end against ghost-ui (attempts 3 / 7 / 8), managerbot, dsgn-playground, cash-ios-moneybot, plus arcade/market expression-fidelity bundles.

Breaking changes

ghost-drift:

  • Public artifact and APIs renamed fingerprintexpression. Default reads expression.md. adopt/parent renamed to track/tracks.
  • Authoring verbs (lint, describe, diff, emit review-command, emit context-bundle) moved to ghost-expression. Library re-exports stay for one major; CLI verbs print a migration message.

ghost-expression:

  • expression.md is an authored-only contract — frontmatter embedding, decisions[].embedding, and the on-disk decision-fragments directory are gone. Existing files must drop those fields.
  • roles[] removed from the schema. Migrate by deleting the section.
  • Bucket → survey rename across schema, CLI, public types, recipes, generated artifacts.
  • Schemas upgraded to ghost.map/v2 and ghost.survey/v2. map.md must declare implemented_surfaces[]; survey.json no longer accepts libraries[].
  • # Signature body section and distinctiveTraits field were dropped, then a different # Signature was reintroduced as final-picture guidance — files carrying the old distinctive-traits-laden shape need to be re-authored.
  • surfaces.shadowComplexity: none renamed to deliberate-none.
  • based_on rule provenance field removed.

ghost-map:

  • Package deleted. Schemas/types live in @ghost/core; verbs and recipe live in ghost-expression.

Test plan

  • pnpm build clean
  • pnpm check clean (biome + typecheck + file-size + cli-manifest)
  • pnpm test — 407 tests across 34 files, all passing locally
  • Lint each in-repo expression.md (fleet members, profile-verifier fixtures, expression-fidelity arcade/market bundles) against the current schema
  • Re-run map → survey → profile end-to-end on at least one dogfood target and confirm verify-profile passes
  • Verify ghost-drift compare self-distance is 0 on every fixture

🤖 Generated with Claude Code

nahiyankhan and others added 27 commits April 29, 2026 15:11
…st-map

Land the bucket pipeline and consolidate to a four-tool topology. A scan
now runs in three stages — topology (map.md) → objective (bucket.json) →
subjective (expression.md) — all owned by ghost-expression.

ghost.bucket/v1: new artifact catalogues every concrete design value with
structured specs, occurrence counts, and deterministic content-hashed IDs.
Schema, lint, merge, and fix-ids primitives live in @ghost/core.

New ghost-expression verbs:
- inventory [path] — raw repo signals JSON (migrated from ghost-map).
- lint [file] — auto-detects expression.md / map.md / bucket.json.
- bucket merge — deterministic concat with id-based dedup, idempotent.
- bucket fix-ids — recompute row IDs from content; lets surveyor agents
  author rows with empty id fields and finalize in one pass.
- scan-status [dir] — report per-stage state and recommended next stage.

New skill recipes (ghost-expression bundle):
- map.md — topology stage (migrated from ghost-map skill recipe).
- survey.md — objective stage. LLM-driven extraction with dialect-specific
  grep strategies, exhaustiveness discipline, saturation predicate.
- scan.md — meta-recipe orchestrating topology → survey → profile.
Refactored: profile.md is now strictly the subjective interpretation
stage (reads bucket.json as ground truth; cannot fabricate values).

ghost-map package deleted. ghost.map/v1 schema/types moved to @ghost/core;
inventory + lint moved to ghost-expression. ghost-fleet now imports map
types from @ghost/core. CLAUDE.md, README.md, and docs IA updated to
reflect the four-tool topology.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…veness

Self-distance reported 17.5% on freshly authored expressions because
loadExpression never backfilled `oklch` on hex-only palette colors.
comparePalette then treated every color as fully unmatched and contributed
distance 1.0 per color even when comparing an expression to itself.

Two-layer fix:
- loadExpression now backfills oklch deterministically (parseColorToOklch
  is pure: same hex → same oklch), so re-parsing produces identical
  in-memory shapes.
- comparePalette resolves oklch on-the-fly when missing and falls back to
  hex-string equality for non-parseable values (CSS vars, opaque refs).
  Defensive against third-party producers that emit hex-only.

Survey recipe tightened with a load-bearing exhaustiveness rule. Triggered
by a dogfood scan that produced ~10% recall on components (6 rows for a
97-component package). The rule is repo-agnostic: the agent identifies the
canonical signal in this repo, enumerates exhaustively, and cross-checks
counts. Recipe explicitly forbids sampling and placeholder/glob library
names. Coverage check (step 8) is now a real gate — exhaustiveness must
match independent counts before declaring saturation.

Pinned attempt-1 artifacts under dogfood/ghost-ui/attempt-1/ with a
structured NOTES.md documenting the failure modes. Future attempts go
alongside so we can track improvement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Recall delta vs attempt 1:
- values:     22  → 190  (10x)
- tokens:     11  → 238  (22x, ~99% of 240 declared in main.css)
- components:  6  →  97  (16x, 100% of registry:ui items)
- libraries:   6  →  42  (7x, every design-surface dep enumerated)

Decision count: 7 → 11. New decisions added — chart-strategy, surface-hierarchy, font-sourcing, density, interactive-patterns — and renames adjusted toward pattern-naming (token-architecture → theming-architecture, shadow-hierarchy → elevation, with the count corrected from 4 tiers to 7).

Self-distance: 0.0% (was 17.5%). Confirms the oklch backfill fix.

Agent followed the recipe by writing build-bucket.mjs (pinned alongside artifacts) — walks main.css for tokens, registry.json for components, package.json for libraries. Reproducible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
External libraries (icon sets, primitive collections, motion libs, charting) no longer have a top-level bucket section. Whether a system uses Radix or hand-rolls primitives doesn't change what its design language *is*; what matters surfaces elsewhere — font families show up as typography tokens, and load-bearing library choices (icon family, font sourcing) belong in interpreter prose under the relevant decision dimension.

Bucket sections are now: values, tokens, components.

Removed from @ghost/core exports: LibraryRow, LibraryRowSchema, libraryRowId. Lint, merge, and fix-ids no longer touch a libraries section. Skill recipes (survey.md, profile.md) updated — survey.md no longer instructs the agent to enumerate libraries; profile.md tells the agent that load-bearing library choices land in prose, not as structured rows.

zod schema stays non-strict, so historical buckets that still carry a libraries field continue to lint clean (the field is simply ignored).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…pology

Six documentation files were carrying stale framing from the five-tool era
or hadn't been updated for the bucket pipeline / libraries-cut.

- packages/ghost-expression/README.md: full rewrite. Was framed around
  "four verbs" (lint/describe/diff/emit) with no mention of the scan
  pipeline. Now leads with the three-stage table (topology → objective →
  subjective), enumerates all seven verbs (inventory, scan-status, lint,
  describe, diff, bucket, emit), and points at all four skill recipes
  (scan, map, survey, profile).

- packages/ghost-drift/README.md: dropped "five-tool decomposition" and
  the ghost-map reference. The "Authoring expression.md?" sidebar now
  surfaces inventory + scan-status + bucket merge alongside the existing
  lint/describe/diff/emit verbs.

- CLAUDE.md / AGENTS.md (symlinked): bucket description no longer mentions
  "and libraries", scan-status added to the verbs table, scan recipe
  added to the workflows list.

- apps/docs/src/content/docs/cli-reference.mdx: added scan-status and
  bucket sections under ghost-expression. Updated overview to seventeen
  verbs and added the scan recipe to the skill-recipes table.

- apps/docs/src/content/docs/getting-started.mdx: tools table grew to
  include scan-status, added a three-stage diagram, replaced the
  single-step "Profile Your First System" with a stage-aware "Scan Your
  First System" walkthrough.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nents

Slot → token bindings either fall out of decisions[] (pattern consequences) or
live in bucket.json components[] (exhaustive catalog). The hybrid roles[]
slot was filling neither cleanly, didn't scale to systems with many components,
and the schema never committed on whether it was exemplary or exhaustive.

Removes roles[] from the zod schema (.strict() now rejects it), Expression
type, lint (broken-role-reference rule, slug-binding propagation, and the
references.ts token resolver), profile/scan/schema/verify/review recipes,
expression.template.md, the docs site, and every fixture (arcade, market,
ghost-ui, fleet members, .scratch). unused-palette is simplified to check
decision evidence/prose only.

Also: ignore .scratch/ for dogfood scans, and ship the ghost-ui
expression-fidelity test bundles (arcade + market) as new fixtures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Free-form `decisions[].dimension` slugs fragment fleet aggregation —
ghost-ui's `color-strategy` and a Cash app's `color-system` describe
the same axis under different names, and N-way overlap on incidentally
shared labels is not a basis for cross-system distance.

Add a 12-slug controlled list in `@ghost/core` (color-strategy,
surface-hierarchy, shape-language, typography-voice, spatial-system,
density, motion, elevation, theming-architecture, interactive-patterns,
token-architecture, font-sourcing) plus `closestCanonical()` and
`resolveDecisionKind()` helpers. The frontmatter schema accepts an
optional `dimension_kind` on `decisions[]` as the escape hatch for
genuinely novel decisions, which fleet-aggregation primitives use to
roll up by canonical bucket. New soft `non-canonical-dimension` lint
warning suggests the closest match without rejecting authoring freedom.

Validated against every expression.md in the repo: the ghost-ui
reference is 11/11 canonical with zero warnings; across 9 expressions,
47 of 64 decisions land canonical, and the matcher resolves 4 of the
remaining 17 to a clear suggestion (`theming` → `theming-architecture`,
`shadow-hierarchy` → `elevation`, `semantic-density` → `density`,
`product-area-color-coding` → `color-strategy`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces the perceptual prior — Ghost's opinionated stance that drift
severity should track how loudly a change registers visually, not just
whether it deviates from a recorded value.

Three perceptual tiers fix membership for each canonical dimension:
loud (color-strategy, font-sourcing → critical), structural (shape,
elevation, surface, interactive, typography-voice → serious), and
rhythmic (spatial-system, density, motion, theming, token → nit).
Match shape is per-RuleKind: color is exact, spacing is band (±2px),
type-size is percent (±10%), radius and shadow are structural.
Presence/absence escalation lifts a rule one tier when bucket count for
its dimension is at or below presence_floor — sparsity is a design
decision, and adding to a silent dimension is the loudest possible
change.

Adds Rule, RuleKind, RuleMatchShape, DriftSeverity types alongside
existing Decision (additive — nothing removed). Expression.rules is
optional. Exports computeRuleSeverity, resolveMatchShape,
resolveTolerance, escalateForPresence as the helpers a v0 emitter
threads the prior through. 35 new tests cover tier coverage, severity
mapping, escalation boundaries, match defaults, and tolerance defaults.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds install/install.sh + install/manifest.json so the Ghost design-
language scan + emit recipes can be installed without npm or a build
step:

    curl -fsSL https://raw.githubusercontent.com/block/ghost/main/install/install.sh | sh

The installer detects the host agent (claude / cursor / codex /
opencode), validates input up-front, fetches the manifest-listed files
under packages/ghost-expression/src/skill-bundle/, and lays them down
under the agent's skills directory (e.g. ~/.claude/skills/ghost/).
Idempotent — refuses to overwrite without --force. Supports
--source <url> for testing against a local mirror or a release fork.
~200 lines of POSIX sh; no Node, no jq dependency. Smoke-tested for
auto-detect, explicit agent, force-reinstall, bad-agent rejection,
and --help.

Pairs with the prose fallbacks already added to scan.md / map.md /
profile.md — the no-CLI install path is real, not degraded.

Also includes the v0 changeset (rules[] + perceptual prior +
curl-install) describing this branch's user-facing impact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Trim the unreleased Rule type before it ships. The field added churn
without earning its keep — re-scan verification can be done by
re-grepping the bucket against the rule's pattern, no per-rule citation
list required. Also keeps the YAML lighter for hand-authors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pair packages/ghost-ui/expression.md with its bucket.json so the
reference design system carries both stage-2 and stage-3 artifacts
side-by-side, like a real consumer would. Earlier dogfood/* attempts
remain as the rough drafts; this is the keeper, scanned at 16f0ab5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
INVARIANTS.md §3 named Character, Signature, and decision rationale as
the body's prose layer. Signature is no longer load-bearing — every
claim it carried is covered better by rules[] (with presence_floor for
absences), decision evidence, or palette/spacing/typography/surfaces
frontmatter — and the section had collapsed into restating other parts
of the artifact.

This is the invariant amendment per INVARIANTS.md's own preamble. The
schema, parser, writer, recipe, template, and existing artifact changes
ship as the next commit (major bump on ghost-expression).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Major bump on ghost-expression. The `# Signature` body section and
`observation.distinctiveTraits` field are removed from the canonical
expression.md schema:

- DesignObservation.distinctiveTraits removed from @ghost/core
- writer no longer emits `# Signature`; lint no longer expects it
- parser silently ignores legacy `# Signature` blocks in older
  expression.md files (graceful migration for downstream consumers)
- profile.md recipe: absences are now codified as rules with
  presence_floor instead of Signature prose
- schema.md / expression-format.md / template / docs site / SKILL.md
  files all updated
- 9 in-repo expression.md files (ghost-ui, fleet fixtures, fidelity
  bundles, dogfood/ghost-ui) rewritten via scripts/strip-signature.mjs
- context-bundle emit uses observation.personality for the trait-phrase
  hooks where it previously used distinctiveTraits

INVARIANTS.md §3 amended in the prior commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
End-to-end ghost-expression scan against an external target — Square's
managerbot app inside the square-web Nx monorepo. Validates the recipe
chain on a real shadcn-flavored design system with AI elements wired in.

map.md      — topology card (the libs/managerbot-ui design-system home)
bucket.json — 459 tokens / 384 distinct values / 103 components
expression.md — 7 rules, 9 decisions, lint clean, self-distance 0.0%

bucket-gen.mjs is the survey-stage generator the recipe authored — kept
inline for reproducibility (run from this directory to regenerate the
bucket against the live target).

Surfaced a few recipe gaps worth noting:

- componentRowId hashes only (source, name) — two components named
  "Message" (ai-elements vs. conversation) collided at fix-ids time.
  Disambiguated via group-prefix in the generator; survey.md should
  document the convention.
- lineHeightPattern enum is tight | normal | loose; managerbot's
  display ramp is genuinely mixed (1.0 on display, ~1.4 on body).
  Picked normal as the closest honest value.
- lint cite-matching is literal — citing var(--neutral-900) doesn't
  satisfy the palette-citation gate; have to inline the resolved
  oklch literal in evidence prose.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-scan packages/ghost-ui end-to-end with the current recipes after the
recent expression schema changes (drop signature section, drop
distinctiveTraits, drop based_on rule provenance). Validates that
ghost-ui's reference design language still profiles cleanly under the
trimmed schema, alongside the managerbot run from b397451.

map.md      — topology card (refreshed mapped_at, language counts)
bucket.json — 169 tokens / 101 distinct values / 97 components
expression.md — 7 rules, 11 decisions, lint clean, self-distance 0.0%

bucket-gen.mjs is the survey-stage generator the recipe authored — kept
inline for reproducibility (rerun from this directory to regenerate the
bucket against the live target).

Component count = 97 = registry:ui count exactly (49 ui/ + 48
ai-elements/), enumerated from registry.json as the canonical signal.
Cross-group name collisions disambiguated via the same group-prefix
convention introduced in the managerbot run.

Surfaced recipe gaps worth folding into survey.md / profile.md:

- `--text-*` namespace is dual-purpose in Tailwind v4: `--text-xxs`
  (typography size) and `--text-default` (foreground color role) share
  the same prefix. Classifier must inspect the resolved literal, not
  just the name. survey.md's Tailwind-v4 entry should call this out.
- `@theme inline` re-exports of the form `--color-X: var(--X)` are a
  mechanical Tailwind class-atom layer with no design information.
  Filtered them out as noise; survey.md should document the filter.
- clamp()-bounded font sizes can't reduce to a single px; honest
  reading is to extract min/max as separate sizeRamp entries.
  profile.md's typography step should mention this.
- Tailwind class-atom spacing (`p-2`, `gap-6`) consumes the Tailwind
  default scale, which `--spacing-*` declarations don't surface. The
  bucket honestly captures only declared `--spacing-*` tokens, leaving
  the spacing scale sparse vs. the actual rendered scale. profile.md
  should note the gap (or survey.md should add a class-atom pass).
- Spacing-scale honesty surfaced a real semantic shift: baseUnit went
  from 4 to null and regularity from 0.8 to 0.5 once the scale was
  bucket-only. Worth re-examining whether the canonical
  packages/ghost-ui/expression.md should track the bucket strictly or
  reflect the rendered (Tailwind-default-augmented) scale.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tailwind targets render most of their design language from class atoms
(`p-2`, `bg-orange-500`, `text-sm`) that consume framework defaults —
the spacing scale is `N * --spacing` (4px-base) by default, with most
N values never declared as `--spacing-N` tokens in `@theme {}`. A
bucket built from declarations alone undercounts the rendered scale
systematically and produces an irregular `expression.spacing.scale`
even when the live UI sits on a clean modular grid.

Surfaced by the ghost-ui dogfood at edc0913: declarations-only pass
produced spacing scale [20, 32, 44, 52, 75, 100], baseUnit null,
regularity 0.5 — vs. the canonical (curated) [2, 4, 6, 8, 12, 16, 20,
24, 32, 36, 40, 52, 75, 100], baseUnit 4. Resolving the actually-used
class atoms (`rg -oN '\bp[lrtbxy]?-N\b' | resolve to N*4px`) recovers
13 of the 14 canonical values at occurrence floor 2.

Adds a `## Tailwind class-atom pass` section between extraction step 2
and step 3 spelling out:

- the v4 atom-to-literal resolver (calculated from `--spacing`,
  overrideable per N via `--spacing-N` declarations)
- the v3 fallback (read `theme.*` from `tailwind.config.{ts,js}`)
- the procedure: grep atoms, resolve to literals, record as
  `values[]` rows with `usage.className`, plus tokens[] rows for the
  Tailwind defaults consumed
- merge-on-collision behavior when a literal comes from both a
  declared token and class-atom usage

Existing `bucket-gen.mjs` generators in dogfood/* don't implement the
pass yet — they still produce declarations-only buckets. A follow-up
attempt-4 would re-validate end-to-end.
Make expression.md the generation and drift root with references, signature, and checks, and add a fresh ghost-ui dogfood scan.
Reframe references as local provenance (not the primary contract), add
guidance that Character/Signature/Decisions describe the language directly
instead of introducing the repo by name, and steer evidence toward
portable survey-grounded patterns with file paths only as optional
provenance. Updates the profile/scan/schema recipes, the SKILL/template,
the writer-emitted prompt.md, and the home-page thesis. Renames the
orphan-prose lint code to orphan-dimension.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures map.md, survey.json, and expression.md for the dsgn-playground
target as a fresh dogfood run against the portability-tightened recipes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both scan schemas bump to /v2. `map.md` adds `surface_sources` (renderable
include/exclude paths, render strategy, coverage gaps) so the survey stage
knows where actual implemented UI lives. `survey.json` adds a top-level
`ui_surfaces[]` section catalogueing routes, stories, screens, fixtures,
docs examples, screenshots, and source-only surfaces, each with kind,
locator, renderability, optional classification (intent / surface_type /
density / layout_shape / confidence) and signals (dominant components,
layout patterns, breakpoint behaviour, value refs, notes).

Library: zod schemas, types, lint, merge, fix-ids, and id helpers updated
across `@ghost/core`. Recipes: map/survey/profile and the SKILL get
revised guidance for the new sections; profile uses ui_surfaces to ground
Character/Signature/Decisions. CLI: `lint-map` and `scan-status` track
the new surface stage. Tests + fixtures upgraded to v2; new
surface-profile fixture covers the profile-from-surfaces path.

Breaking: existing v1 maps and surveys no longer validate. Re-run map
and survey stages to upgrade.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures map.md, survey.json, and expression.md against schema v2 with
implemented-surface evidence, plus the build-survey.mjs script used to
generate the survey from the iOS source tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New survey op that distills a `ghost.survey/v2` file into a compact
profile digest — Markdown by default, JSON with `--format json`, with
`compact` / `standard` / `full` budgets. Output covers source provenance,
top-N values per kind with count summaries, token families with theme
breakdowns, component inventory highlights, UI-surface groups, and
resolution status, while preserving row IDs so the agent can fall back
to targeted raw lookups for exact provenance.

Profile and scan recipes now make summary-first the default working
context for stage 3 — agents read the bounded digest end-to-end and
only open `survey.json` when a specific row needs verification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Re-runs the ghost-ui scan using `ghost-expression survey summarize` as
the profile context (compact budget) instead of the full raw survey.
Compact digest is ~5% the size of survey.json and produced a
zero-distance expression vs attempt-6 with no semantic diff, confirming
the summary-first profile path preserves the design-language contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop fragment-era embedding and on-disk decision fragments — embeddings are
recomputed at load time from the authored body, and INVARIANTS.md / its
references are folded into CLAUDE.md. Add `ghost-expression verify-profile`
to check palette provenance and promoted-check calibration against
survey.json, plus a `survey catalog` op for derived value enum/spec views.
Refresh ghost-ui by removing the stale package-root expression/map/survey
artifacts and expression-fidelity bundles, replaced with attempt-8 dogfood
and new profile-verifier fixtures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nahiyankhan nahiyankhan changed the title Three-stage scan pipeline + schema simplification Three-stage scan pipeline + expression-as-authored-contract May 5, 2026
@nahiyankhan nahiyankhan merged commit 12298db into main May 5, 2026
6 checks passed
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