Skip to content

refactor: C2d — compiler-enforced layer boundaries - #1315

Draft
gewenyu99 wants to merge 8 commits into
posthog/functional-c2c-controlfrom
posthog/functional-c2d-enforcement
Draft

gewenyu99 wants to merge 8 commits into
posthog/functional-c2c-controlfrom
posthog/functional-c2d-enforcement

Conversation

@gewenyu99

@gewenyu99 gewenyu99 commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Layer boundaries were enforced by an arch test allowlist and ESLint rules, which don't stop a bad import at compile time.

Change

  • Each layer has a tsc -b project whose paths expose only the entries it may import: env, shared, agent, programs, legacy, headless, tui, cli.
  • Ink and React map to stubs everywhere except the TUI.
  • pnpm typecheck runs tsc --noEmit, then tsc -b tsconfig.layers.json --force, then scripts/boundary-probes.ts (32 probes).
  • The arch test adds a per-program rule: a program folder never imports another program.
  • The known-violations allowlist is deleted, with zero violations left.

Checks

Typecheck, lint, unit tests, the arch test and the bundle build pass.

Created with PostHog Desktop

@tui and @Headless are the runtime entries, @tui/types and @headless/types
the type entries; the CLI no longer imports either surface by path. Nothing
in @tui renders: the Ink pieces (startTUI, the playground, the family
picker) load through loadStartTui, loadPlayground and loadFamilyPicker, and
the control server through @Headless's loadControl, so the startup closure
still holds no Ink and no server. The run-failure check the TUI runner reads
after a run loads with it.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
Inside agent, programs, tui and cli, a module imported its own layer
through the layer alias (`@agent/progress`, `@programs/program-step`). The
compiler enforcement that follows reads other layers only through their
emitted declarations, which keep each import's specifier: an own-layer alias
there would force consumers to resolve deep aliases, which is exactly what
the enforcement forbids. Relative paths resolve inside the declarations
themselves. Tests keep their aliases; no behavior change.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
Each layer is its own TypeScript project (src/<layer>/tsconfig.layer.json,
generated for env, shared, agent, programs, tui, headless, cli and bin) that
compiles its own source and sees the other layers only through their built
declarations, mapped to their public entries. A forbidden layer fails by any
spelling (alias, relative path, dynamic import, type query), a deep import
into an allowed layer fails, the TUI gets agent types and no agent values,
shared and env cannot reach the agent at all, and ink and react resolve to
empty stubs outside the TUI. `pnpm typecheck` builds tsconfig.layers.json
and runs scripts/boundary-probes.ts, 25 probes that must fail or compile as
declared; CI now runs it.

The import scanner, known-violations.json, the architecture Vitest project
and the ESLint boundary overrides are deleted. Building the layers found two
edges the scanner let through, both fixed here: program-store imported agent
and shared source by relative path, and shared's skill error map imported
agent types (InstallSkillResult now lives in shared). bin.ts drops the dead
NODE_ENV=test mock-server hook, which reached into e2e-tests.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
@github-actions

Copy link
Copy Markdown

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci ai-observability
  • /wizard-ci basic-integration
  • /wizard-ci mcp-analytics
  • /wizard-ci replay-vision
  • /wizard-ci revenue
  • /wizard-ci self-driving
  • /wizard-ci warehouse
  • /wizard-ci warehouse-seeded

Test an individual app:

  • /wizard-ci ai-observability/anthropic
  • /wizard-ci ai-observability/google-adk
  • /wizard-ci ai-observability/groq
Show more apps
  • /wizard-ci ai-observability/manual-capture
  • /wizard-ci ai-observability/openai
  • /wizard-ci ai-observability/openai-agents
  • /wizard-ci ai-observability/opentelemetry
  • /wizard-ci ai-observability/vercel-ai
  • /wizard-ci basic-integration/android
  • /wizard-ci basic-integration/angular
  • /wizard-ci basic-integration/astro
  • /wizard-ci basic-integration/django
  • /wizard-ci basic-integration/fastapi
  • /wizard-ci basic-integration/flask
  • /wizard-ci basic-integration/flutter
  • /wizard-ci basic-integration/javascript-node
  • /wizard-ci basic-integration/javascript-web
  • /wizard-ci basic-integration/laravel
  • /wizard-ci basic-integration/next-js
  • /wizard-ci basic-integration/nuxt
  • /wizard-ci basic-integration/python
  • /wizard-ci basic-integration/rails
  • /wizard-ci basic-integration/react-native
  • /wizard-ci basic-integration/react-router
  • /wizard-ci basic-integration/sveltekit
  • /wizard-ci basic-integration/swift
  • /wizard-ci basic-integration/tanstack-router
  • /wizard-ci basic-integration/tanstack-start
  • /wizard-ci basic-integration/vue
  • /wizard-ci mcp-analytics/custom-dispatcher
  • /wizard-ci mcp-analytics/typescript-sdk
  • /wizard-ci replay-vision/javascript-node
  • /wizard-ci replay-vision/next-js
  • /wizard-ci replay-vision/react-vite
  • /wizard-ci revenue/stripe
  • /wizard-ci self-driving/astro
  • /wizard-ci self-driving/fastapi
  • /wizard-ci self-driving/nuxt
  • /wizard-ci self-driving/react-router
  • /wizard-ci self-driving/sveltekit
  • /wizard-ci warehouse/monorepo-env
  • /wizard-ci warehouse/multi-source-next
  • /wizard-ci warehouse/stripe-node
  • /wizard-ci warehouse/zero-source
  • /wizard-ci warehouse-seeded/next-stripe
  • /wizard-ci warehouse-seeded/next-stripe-declined

Test against a Context Mill branch:

  • /wizard-ci all context-mill:my-branch

Add context-mill:<branch> to any command above to pin the Context Mill branch. It defaults to main.

Results will be posted here when complete.

…rcement

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
Merge the restacked C2c (611c5bb) into C2d. The conflicts are import
blocks: C2d's rule that a layer imports its own modules by relative path
applies to the fix's new imports too, including `pi/gateway.ts`. The
root `tsconfig.json` keeps only the `.tsbuild` exclude, because the
e2e-tests package is gone.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
Merge the restacked posthog/functional-c2d-enforcement (4d2bf0b) and the new base (bf78885). The tree matches 4d2bf0b, where typecheck, lint and tests pass.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
Merge the joined C2c (a944edc) into C2d:

- The scanner, its allowlist and the ESLint boundary overrides stay
  deleted, and so do the deck wrappers B removed.
- B's new imports follow C2d's rule that a layer imports its own modules
  by relative path: the skill preflight in `tools.ts`, `signals` in the
  Anthropic harness, credentials in detection, `flows` in the learn-deck
  demo, and the CLI's own modules.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
@gewenyu99 gewenyu99 changed the title build: C2d enforce layer boundaries with the TypeScript compiler refactor: C2d — compiler-enforced layer boundaries Sep 24, 2026
One tsc -b project per layer, UI stubs outside the TUI, 32 boundary probes, and a per-program isolation rule in the arch test. The allowlist is gone: zero violations.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
Base automatically changed from posthog/functional-c2c-control to posthog/functional-c2b-headless September 27, 2026 15:19
@gewenyu99
gewenyu99 force-pushed the posthog/functional-c2d-enforcement branch from 90b8d71 to abcff7b Compare September 27, 2026 15:24
@gewenyu99
gewenyu99 changed the base branch from posthog/functional-c2b-headless to posthog/functional-c2c-control September 27, 2026 15:26
@gewenyu99
gewenyu99 added this pull request to stack #1372 September 27, 2026 15:28
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