Skip to content

Ghost stack 1/6 — Layer-2 design reset & surface-model spec (docs)#189

Draft
nahiyankhan wants to merge 9 commits into
mainfrom
ghost/01-surface-spec
Draft

Ghost stack 1/6 — Layer-2 design reset & surface-model spec (docs)#189
nahiyankhan wants to merge 9 commits into
mainfrom
ghost/01-surface-spec

Conversation

@nahiyankhan

Copy link
Copy Markdown
Collaborator

Stacked PR 1 of 6 · base: `main`

Design reset and the surface-model contract that the rest of the stack builds on. Docs/spec only — no runtime code.

Contents

  • Reset Ghost around a clean Layer 2 design
  • Split containment tree from composition graph (coordinate-space)
  • Propose `ghost.surfaces/v1` schema; settle edge_kinds, flat ids, explicit placement
  • Settle `ghost.binding/v1` repo binding layer
  • Sequence the hard-cutover surface-model build; phase-1 execution spec

Stack order

  1. ➡️ ghost/01-surface-spec (this PR)
  2. ghost/02-surface-model
  3. ghost/03-polish-cuts
  4. ghost/04-one-road
  5. ghost/05-node-graph
  6. ghost/06-cleanup

Merge bottom-up. Each PR targets the branch below it.

Stop circling. Three notes (purposes, ghost-layers, contract-and-binding)
shared one diagnosis: the descriptive core is clean; selection/routing/merge
leaked into the artifact's shape. reset.md fixes purpose, goals, layers, and
separation of concerns, and schedules a single first cut. coordinate-space.md
is the clean-room Layer 2 design: a surface is an author-named group with an
optional description; topology is a strict containment tree plus
cascade-from-ancestors plus rare explicit shared-edges; resolution is BYOA
(Ghost emits a described menu, the agent matches); delete list covers
inventory.topology, smeared applies_to, and ghost.map/v1.

Focus pass: delete pre-redesign docs (fingerprint-format, generation-loop,
host-adapters, ghost-fleet, language-fingerprints, relay-configs-and-context,
prompt-first-relay-prd) that described the dead Relay-routing and
topology/applies_to model. Port the one durable thesis (language maps onto the
four facets) inline into the voice skill reference and fix its stale coordinate
guidance. Update README and ideas/README to the reset arc.
A real non-UI composition case showed the topology conflated two axes.
Containment (where a node lives, who owns it) is a Layer 2 strict tree with
cascade-from-ancestors. Composition (what combines to serve a request) is a
Layer 3 typed reference graph laid over the tree. The explicit edges are not a
rare exception; in composition-heavy, pathless cases they are the primary
structure. The original 'tree + rare edges' framing over-fit the in-repo UI
case and under-served the no-repo composition case. Amends the topology section,
the layer-asks, decision 3, the surface shape, read-back, and the ideas README.
First concrete cut from coordinate-space.md. Proposes a new surfaces.yml facet
(ghost.surfaces/v1) anchored by the existing manifest, expressing both axes:
parent (the containment tree) and typed edges over edge_kinds (the composition
graph). Specifies a field-by-field migration off inventory.topology, smeared
applies_to, and exemplar surface_type/scope to a single surface: placement
pointer, keeping Layer 1 prose constant and the flat facet files intact for the
first cut. Includes a worked example from this repo's own dogfood .ghost/, lint
obligations, and open forks (closed vs open edge_kinds, dotted ids, default
placement, where path->surface mapping lives). Additive and backward compatible:
absent surfaces.yml keeps single-core behavior.
Resolve two open forks into decisions. edge_kinds is a fixed, Ghost-owned,
closed set referenced (never defined) per package: opening it would make Ghost a
general-purpose graph database and lose the interface-composition focus; richer
consumers extend edges consumer-side, not by opening Ghost's set. IDs are flat,
unique slugs with no structural meaning; dotted-id-as-hierarchy is banned (lint
error) so the tree lives only in parent, one source of truth (kills Leak C).
Updates the example, field rules, lint obligations, and forks list; two forks
remain (surface default, path->surface binding).
…coped ownership

Resolve the remaining forks. Placement is explicit: defaulting un-placed nodes
to core would rebuild global-fallback (the brand-mixing failure the redesign
cures), so authoring drafts placement, lint warns-and-teaches on the gap, and
un-placed never silently means core (warning not error, matching the derivation-
ref convention).

Reframe the path->surface fork as scoped ownership: in a repo, surfaces are
owned by location (the checkout surface is realized under apps/checkout), which
is ordinary nested-package/CODEOWNERS-shaped binding, not a new subsystem. The
portable contract (surfaces.yml) carries no paths; paths live on the binding.
One sub-fork remains for its own note: nested-package-as-binding vs explicit
path declaration vs both.
Second concrete extraction. The contract (surfaces.yml) carries no paths; the
binding owns all path matching. Directory location is the default binding (a
scoped .ghost/ binds surfaces to its subtree, reframing nested-package
resolution from data-merge to binding); an explicit .ghost.bind.yml is the
escape hatch when ownership does not match the tree, and is the real home for
the deleted topology.scopes[].paths. One resolver serves prompt, path, and diff
roads, meeting at a surface id; no-repo cases need no binding. Reframes
nesting-as-ownership to retire Leak E (no silent merge override, no silently
disabled inherited critical check). Records open forks (external contract
references, core fallback, bind-vs-redeclare) and the honest caution that this
is the least proof-validated layer, so it ships smallest-first.
Plan the breaking change as eight dependency-ordered phases, each a green,
committed cut: (0) freeze/baseline, (1) ghost.surfaces/v1 schema, (2) surfaces
lint, (3) placement on nodes — the breaking line, removing topology/applies_to/
surface_type/scope, (4) delete ghost.map/v1, (5) slice resolver + menu (prompt
road), (6) one-shot migration command + migrate this repo's .ghost/, (7)
ghost.binding/v1 path/diff roads + retire child-wins-by-id (Leak E), (8) command/
skill/docs reconciliation. Measured blast radius (~38 src, ~16 map, ~20 test
files). Additive phases 1-2 land first to de-risk; least-validated binding lands
last. Records open planning decisions (relay survival, migrator permanence,
delete-list commands).
…s test

A command's desire survives if the new model serves it; its implementation
survives only if it already is that. Relay's desire (right narrow context, right
time, traceable) is realized by the Phase 5 resolver; relay's implementation
(relay-config, request_resolvers, sources, ghost.relay-request/v1) is the second
routing system on the delete list. So relay/stack/survey/diff/describe are
deleted: relay and stack absorbed into a new gather/select command shipped in
Phase 5, the rest dead. Phase 5 ships the new context command on the resolver
(not old relay plumbing); Phase 8 deletes the dead commands as execution, not
decision. Collapses three open planning decisions into one.
…odule

First implementation cut, purely additive. Specs a new ghost-core/surfaces/
module mirroring fingerprint/ (types, schema, index) plus a schema test and one
re-export in ghost-core/index.ts. Schema bans dotted ids via a dot-excluding
slug regex (the tree lives only in parent); single parent falls out of parent
being scalar; edge kinds restricted to the fixed Ghost-owned set. Draws an
explicit schema/lint boundary: graph-level checks (cycles, dangling parent/edge
refs, near-miss, reserved core) are deferred to Phase 2 lint, documented in a
test case so they are not fixed in the wrong layer. Out-of-scope and acceptance
criteria are enumerated; one commit, no changeset (no user-visible behavior).
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