Merge branch 'worktree-fallow-integration-v1': fallow v1 — 5th gate (whole-codebase)
Some checks failed
CI / typecheck + lint + boundaries + test + build (push) Has been cancelled
CI / Playwright e2e (push) Has been cancelled
CI / Storybook smoke tests + visual regression (push) Has been cancelled
Sentry PII guard (R31) / pii-guard (push) Has been cancelled

This commit is contained in:
2026-05-13 08:57:42 +02:00
15 changed files with 397 additions and 46 deletions

62
.fallowrc.json Normal file
View File

@@ -0,0 +1,62 @@
{
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
"ignorePatterns": [
"**/node_modules/**",
"**/dist/**",
"**/.next/**",
"**/.turbo/**",
"**/storybook-static/**",
"**/__snapshots__/**",
"**/turbo/generators/templates/**",
"**/*.generated.ts",
"**/*.d.ts"
],
"dynamicallyLoaded": [
"packages/**/__factories__/**",
"packages/**/__seeds__/**",
"apps/**/instrumentation.ts",
"apps/**/instrumentation-client.ts",
"apps/storybook/test-runner.config.ts",
"scripts/**/*.mjs"
],
"publicPackages": ["@repo/core-*"],
"ignoreDependencies": [
"@payloadcms/ui",
"sass",
"sharp",
"@tanstack/react-query",
"@trpc/server",
"superjson",
"@repo/blog",
"@repo/core-api",
"@repo/marketing-pages",
"@repo/navigation",
"@repo/core-testing",
"http-server",
"wait-on",
"@opentelemetry/api-logs",
"@typescript-eslint/eslint-plugin",
"@testing-library/user-event",
"zod",
"@eslint/js",
"@opentelemetry/sdk-node",
"@sentry/opentelemetry"
],
"ignoreExportsUsedInFile": true,
"rules": {
"unused-files": "warn",
"unused-exports": "warn",
"unused-types": "off",
"unused-class-members": "warn",
"unused-dependencies": "warn",
"unused-dev-dependencies": "warn",
"unlisted-dependencies": "warn",
"circular-dependencies": "error",
"duplicate-code": "warn"
},
"health": {
"maxCyclomatic": 25,
"maxCognitive": 30,
"maxCrap": 400
}
}

View File

@@ -50,6 +50,8 @@ jobs:
- run: pnpm typecheck
- run: pnpm lint
- run: pnpm conformance
- name: Fallow whole-codebase analysis
run: pnpm fallow --format annotations
- run: pnpm turbo boundaries
- name: Test with coverage
env:

View File

@@ -41,9 +41,10 @@ pnpm typecheck # TS brand-slot enforcement, 0s
pnpm lint # ESLint rules incl. conformance/* — <1s
pnpm test --filter @repo/<feature> # tests for the feature you touched
pnpm conformance # cross-feature event closure
pnpm fallow:audit # whole-codebase analysis: dead exports, dupes, circular deps, complexity
```
All four pass before you commit. If any fail, fix or report BLOCKED — do not paper over.
All five pass before you commit. If any fail, fix or report BLOCKED — do not paper over.
## Commit message format

View File

@@ -31,6 +31,7 @@ If you suspect the implementer hand-rolled what should have been generator outpu
3. **Manifest-first ordering**: if a new use case landed, the manifest was updated; tests exist; the factory was wrapped at bind time.
4. **Conformance gates**: the diff's tests + lint + typecheck pass. (You don't run them yourself; sandcastle's CI step does. Trust the CI status, reject if it's red.)
5. **Generator-first**: see the section above. Hand-rolled code that should have been generated is a rejection.
6. **Fallow audit**: verify the implementer ran `pnpm fallow:audit` and it passed. If their diff increases dead exports / dupes / circular deps / complexity beyond the baseline, that's a rejection cause unless the implementer's notes explicitly justify it.
## Output format

View File

@@ -39,23 +39,24 @@ Turborepo + pnpm monorepo organized by vertical features. Each feature (`auth`,
- `docs/architecture/vertical-feature-spec.md` — Design spec with rationale and decision log
- `docs/guides/scaffolding-a-feature.md``turbo gen feature` reference (fast path; prefer this over the manual walkthrough)
- `docs/guides/adding-a-feature.md` — End-to-end new feature walkthrough (manual path; for cases the generator's Phase-1 scope doesn't cover)
- `docs/guides/events-and-jobs.md` — publish/consume/schedule cookbook (cross-feature events + background jobs; *requires `gen core-package events`*)
- `docs/guides/realtime.md` — Socket.IO channels, broadcasts, handlers (*requires `gen core-package realtime`*)
- `docs/guides/audit-and-compliance.md` — DPA-compliant audit logging cookbook (*requires `gen core-package audit`*)
- `docs/guides/events-and-jobs.md` — publish/consume/schedule cookbook (cross-feature events + background jobs; _requires `gen core-package events`_)
- `docs/guides/realtime.md` — Socket.IO channels, broadcasts, handlers (_requires `gen core-package realtime`_)
- `docs/guides/audit-and-compliance.md` — DPA-compliant audit logging cookbook (_requires `gen core-package audit`_)
- `docs/architecture/template-tiers.md` — must-have vs optional packages and how to scaffold the optionals
## Conformance system
Every feature has a `src/feature.manifest.ts` declaring its use cases, audits, publishes, consumes, and required cores. Drift is caught at four latencies:
Every feature has a `src/feature.manifest.ts` declaring its use cases, audits, publishes, consumes, and required cores. Drift is caught at five latencies:
| Layer | Latency | Catches |
|---|---|---|
| -------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| **TypeScript brands** | 0s | forgotten `withSpan` / `withCapture` / `withAudit` at bind time |
| **ESLint rules** | <1s | manifest code drift; undeclared `bus.publish` / `auditLog.record`; missing manifest; missing sibling test |
| **Boot assertion** (`pnpm dev`) | ~3s | binding without required brand at runtime; manifest edited without rebinder |
| **CI drift gate** (`pnpm conformance`) | ~120s | orphan event consumers across features |
| **Fallow** (`pnpm fallow`) | ~3060s | dead exports / unused files; duplicate code; circular deps; complexity hotspots; AI-change audit drift |
The five conformance ESLint rules: `feature-must-have-manifest` (error), `usecase-must-have-test-file` (error), `required-cores-installed` (error), `no-undeclared-event-publish` (warn), `no-undeclared-audit` (warn).
The five conformance ESLint rules: `feature-must-have-manifest` (error), `usecase-must-have-test-file` (error), `required-cores-installed` (error), `no-undeclared-event-publish` (warn), `no-undeclared-audit` (warn). Fallow runs as a fifth layer, post-ESLint, whole-codebase.
See `docs/architecture/agent-first-workflow-and-conformance.md` for the full design and `docs/guides/conformance-quickref.md` for the day-to-day reference.
@@ -83,11 +84,11 @@ See `docs/architecture/agent-first-workflow-and-conformance.md` for the full des
- **PII handling is non-negotiable** `sendDefaultPii: false` everywhere (R31, CI grep gate); replay default-masks all text/inputs/media (R34, R35, allowlist starts empty); `setUser({ id })` only no email/username (R36); server-side PII scrubbing happens at the OTel processor layer (`PiiScrubSpanProcessor` + `PiiScrubLogRecordProcessor`) before any exporter sees the data (R32, R33, ADR-017 §7)
- **Three apps, three Sentry projects** `WEB_NEXT_SENTRY_DSN`, `CMS_SENTRY_DSN`, `WEB_TANSTACK_SENTRY_DSN`. Browser DSNs use `NEXT_PUBLIC_` (web-next) and `VITE_` (web-tanstack) prefixes
- **Instrumentation binding is orthogonal to repo binding** `bindAll()`'s Rule 0 (DSN OTel+Sentry vs Noop) is independent of `USE_DEV_SEED` / `NODE_ENV`. Run `pnpm dev` with `WEB_NEXT_SENTRY_DSN` set to test the integration locally
- **Cross-feature events go through `IEventBus` (E0)** In-feature reactions are direct use-case calls, not bus publishes. The bus is for *crossing* feature boundaries (e.g. `auth` `marketing-pages` welcome email)
- **Cross-feature events go through `IEventBus` (E0)** In-feature reactions are direct use-case calls, not bus publishes. The bus is for _crossing_ feature boundaries (e.g. `auth` `marketing-pages` welcome email)
- **Event contracts are public; handlers are private (E1)** Publisher's `events/<x>.event.ts` is exported from the feature root barrel. Consumer's `events/handlers/on-<publisher>-<event>.handler.ts` is never re-exported (ESLint-enforced via `core-eslint/rules/no-handler-reexport`)
- **Jobs are for *deferred* work, not abstraction (J0)** Synchronous code stays synchronous. A job exists only when something must run off the request path (latency, retries, cron). Feature packages enqueue via `IJobQueue` only direct `payload.jobs.queue()` is ESLint-blocked outside `core-shared/jobs/`
- **Jobs are for _deferred_ work, not abstraction (J0)** Synchronous code stays synchronous. A job exists only when something must run off the request path (latency, retries, cron). Feature packages enqueue via `IJobQueue` only direct `payload.jobs.queue()` is ESLint-blocked outside `core-shared/jobs/`
- **Realtime is for state delivery, not for replacing tRPC (R0)** Persistent request/response operations belong on tRPC procedures. Use realtime when the server needs to push without a request or the data is too high-frequency for HTTP
- **Realtime channel descriptors are exported; handlers are private (R1)** A feature's `realtime/<name>.channel.ts` is re-exported from the root barrel; `realtime/handlers/*.handler.ts` is wired only in bind-* files and never re-exported (ESLint-enforced via `no-realtime-handler-reexport`)
- **Realtime channel descriptors are exported; handlers are private (R1)** A feature's `realtime/<name>.channel.ts` is re-exported from the root barrel; `realtime/handlers/*.handler.ts` is wired only in bind-\* files and never re-exported (ESLint-enforced via `no-realtime-handler-reexport`)
- **`socket.io` lives in `@repo/core-realtime` only (R2)** Feature packages MUST NOT import `socket.io` or `socket.io-client`. ESLint rule `no-direct-socket-io` enforces this; allowlist covers `core-realtime/src/socket-io-*.ts` and `apps/*/server.ts`
- **Manifest-first ordering** for any new use case, the workflow is **(1) manifest entry** **(2) contracts** (`xInputSchema`, `xOutputSchema`, `IXUseCase`) **(3) tests (red)** **(4) implementation (green)**. The generator emits the manifest + a self-asserting `bind-production.ts` so new features are conformance-compliant by default
- **Self-asserting `bindProductionX(ctx)`** every feature's bind-production calls `assertFeatureConformance(container, manifest, symbols, ctx)` at its tail. `pnpm dev` refuses to boot on drift
@@ -102,7 +103,7 @@ Storybook MCP available at `http://localhost:6006/mcp` — use `list-all-documen
## Key Ports
| Service | Port |
|---|---|
| -------------- | ---- |
| Next.js | 3000 |
| Payload CMS | 3001 |
| TanStack Start | 3002 |

View File

@@ -33,7 +33,7 @@ export type FooManifest = typeof fooManifest;
Field reference:
| Field | Type | Meaning |
|---|---|---|
| --------------------------- | -------------- | --------------------------------------------------------------------------- |
| `name` | string literal | Feature name (kebab-case, matches package name) |
| `requiredCores` | string[] | Optional cores this feature requires (e.g. `["audit", "events"]`) |
| `useCases.<name>.mutates` | boolean | True for create/update/delete; drives whether `__audited` brand is required |
@@ -74,19 +74,20 @@ export function bindProductionFoo(ctx: BindProductionContext): void {
The symbol map declares which container symbol each manifest use-case key resolves to.
## The four gates
## The five gates
| Gate | When it fires | What it catches | Severity |
|---|---|---|---|
| ------------------ | --------------------- | ------------------------------------------------------------------------ | -------------------- |
| `tsc` | on save | forgotten wrappers; manifest-derived slot type rejects unwrapped factory | error |
| `eslint` | on save / `pnpm lint` | manifest ↔ code drift; missing sibling test; missing manifest | error or warn |
| `pnpm dev` | at boot | binding lost its runtime brand; manifest declares more than wired | throws synchronously |
| `pnpm conformance` | CI | orphan event consumers across features | exits non-zero |
| `pnpm fallow` | ~3060s | unused exports/files, dupes, circular deps, complexity, AI-change audit | warn (currently) |
## ESLint rules
| Rule | Severity | What it does |
|---|---|---|
| ----------------------------------------- | -------- | -------------------------------------------------------------------------------------- |
| `conformance/feature-must-have-manifest` | error | Use-case files require a sibling manifest |
| `conformance/usecase-must-have-test-file` | error | Every `*.use-case.ts` has a sibling `*.use-case.test.ts` |
| `conformance/required-cores-installed` | error | Manifest's `requiredCores` must exist as `core-<name>` packages in pnpm-workspace.yaml |
@@ -119,6 +120,18 @@ When a gate fires, the error message tells you what to run. For example:
That's the "fix" line — follow it.
## Fallow audit for AI changes
When you (the agent) finish a task and are about to commit, run:
```
pnpm fallow:audit
```
This runs `fallow audit --base main`, comparing your branch's diff against main. If your change adds dead exports, dupes, or complexity hotspots, fallow tells you exactly what and where. Fix or accept (with --gate flag to ignore inherited findings).
This is the catch-all for whole-codebase drift the per-file gates can't see.
---
For the deeper design rationale see `docs/architecture/agent-first-workflow-and-conformance.md` and the interactive `feature-conformance-explainer.html`.

View File

@@ -1,5 +1,5 @@
{
"updated_at": "2026-05-13T06:32:59.719Z",
"updated_at": "2026-05-13T06:55:52.068Z",
"epics": {
"agent-workflow-docs-v1": {
"status": "done",
@@ -202,6 +202,56 @@
}
}
},
"fallow-integration-v1": {
"status": "done",
"title": "Fallow integration v1 — whole-codebase static analysis as 5th gate",
"stories": {
"01-fallow-install": {
"status": "done",
"title": "Install fallow + create .fallowrc.json",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [],
"blocks": [
"02-pnpm-turbo-wiring"
]
},
"02-pnpm-turbo-wiring": {
"status": "done",
"title": "pnpm script + turbo task wiring",
"ac_total": 4,
"ac_completed": 4,
"depends_on": [
"01-fallow-install"
],
"blocks": [
"03-ci-integration"
]
},
"03-ci-integration": {
"status": "done",
"title": "CI workflow runs pnpm fallow",
"ac_total": 2,
"ac_completed": 2,
"depends_on": [
"02-pnpm-turbo-wiring"
],
"blocks": [
"04-docs-and-prompts"
]
},
"04-docs-and-prompts": {
"status": "done",
"title": "Docs + agent prompt updates",
"ac_total": 5,
"ac_completed": 5,
"depends_on": [
"03-ci-integration"
],
"blocks": []
}
}
},
"frontend-conformance-v1": {
"status": "done",
"title": "Frontend conformance rules v1",

View File

@@ -0,0 +1,17 @@
---
id: 01-fallow-install
epic: fallow-integration-v1
title: Install fallow + create .fallowrc.json
type: technical-story
status: done
feature: tooling
depends-on: []
blocks: [02-pnpm-turbo-wiring]
---
## Tasks
- [x] Story scaffold
- [x] Add fallow to root devDependencies
- [x] Create .fallowrc.json with monorepo-aware config
- [x] Verify `pnpm exec fallow --version` works

View File

@@ -0,0 +1,17 @@
---
id: 02-pnpm-turbo-wiring
epic: fallow-integration-v1
title: pnpm script + turbo task wiring
type: technical-story
status: done
feature: tooling
depends-on: [01-fallow-install]
blocks: [03-ci-integration]
---
## Tasks
- [x] pnpm fallow script (runs all)
- [x] pnpm fallow:audit script (runs `fallow audit --base main`)
- [x] turbo.json task entry for fallow
- [x] Run `pnpm fallow` against current repo, capture findings, tune config

View File

@@ -0,0 +1,15 @@
---
id: 03-ci-integration
epic: fallow-integration-v1
title: CI workflow runs pnpm fallow
type: technical-story
status: done
feature: ci
depends-on: [02-pnpm-turbo-wiring]
blocks: [04-docs-and-prompts]
---
## Tasks
- [x] Add `pnpm fallow` step after `pnpm conformance` in ci.yml
- [x] Use --format annotations for inline GH PR comments

View File

@@ -0,0 +1,18 @@
---
id: 04-docs-and-prompts
epic: fallow-integration-v1
title: Docs + agent prompt updates
type: technical-story
status: done
feature: agent-prompts
depends-on: [03-ci-integration]
blocks: []
---
## Tasks
- [x] Update CLAUDE.md conformance-system section to list Fallow as 5th gate
- [x] Update docs/guides/conformance-quickref.md with Fallow row
- [x] Update .sandcastle/implementer.prompt.md: run `fallow audit` before commit
- [x] Update .sandcastle/reviewer.prompt.md: verify implementer ran fallow audit
- [x] Final verification + closeout

View File

@@ -0,0 +1,28 @@
---
id: fallow-integration-v1
prd: null
title: Fallow integration v1 — whole-codebase static analysis as 5th gate
type: epic
status: done
features: [tooling, ci, agent-prompts]
created: 2026-05-13
---
## Goal
Wire Fallow as the 5th conformance gate: install, configure, pnpm script,
turbo task, CI step, docs update, agent prompt update.
## Why
Fallow catches what file-local lint, type-check, manifest assertions, and
conformance event closure cannot — dead code, dupes, circular deps,
complexity hotspots, and AI-change drift. `fallow audit --base main` is
purpose-built for AI agents to self-validate before submission.
## Stories
- [x] [01 — Install fallow + .fallowrc.json](01-fallow-install/_story.md)
- [x] [02 — pnpm + turbo wiring](02-pnpm-turbo-wiring/_story.md)
- [x] [03 — CI workflow integration](03-ci-integration/_story.md)
- [x] [04 — Docs + agent prompt updates](04-docs-and-prompts/_story.md)

View File

@@ -15,6 +15,8 @@
"test:visual": "pnpm --filter @repo/storybook exec concurrently -k -s first -n 'SB,VRT' -c 'magenta,blue' 'pnpm --filter @repo/storybook exec http-server storybook-static --port 6006 --silent' 'pnpm --filter @repo/storybook exec wait-on tcp:6006 && pnpm exec playwright test'",
"typecheck": "turbo run typecheck",
"conformance": "node scripts/conformance.mjs",
"fallow": "fallow",
"fallow:audit": "fallow audit --base main",
"work": "node scripts/work/cli.mjs",
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"",
@@ -25,6 +27,7 @@
"@playwright/test": "^1.49.0",
"@turbo/gen": "^2.4.0",
"@types/node": "^22.0.0",
"fallow": "^2.73.0",
"husky": "^9.0.0",
"lint-staged": "^16.0.0",
"prettier": "^3.5.0",

112
pnpm-lock.yaml generated
View File

@@ -19,6 +19,9 @@ importers:
"@types/node":
specifier: ^22.0.0
version: 22.19.17
fallow:
specifier: ^2.73.0
version: 2.73.0
husky:
specifier: ^9.0.0
version: 9.1.7
@@ -2289,6 +2292,70 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
"@fallow-cli/darwin-arm64@2.73.0":
resolution:
{
integrity: sha512-4mo+35ufU3H5HpyYi/UT12EvRJA7ibglIaWTDqjc6TkZoz7fXYKh9PT+KcBBZyMbFC1kvAxJsfJP1J4zKXr5xQ==,
}
cpu: [arm64]
os: [darwin]
"@fallow-cli/darwin-x64@2.73.0":
resolution:
{
integrity: sha512-bgob14wLLRXTXI+/XMT7OhVIZV1aBw0lvlXJwl/+t8MOUftlG68VoZVRkpzDypWc/dPxsa5J72kUv/5b1F/jXg==,
}
cpu: [x64]
os: [darwin]
"@fallow-cli/linux-arm64-gnu@2.73.0":
resolution:
{
integrity: sha512-7q058FGiv92VCMikoaNkcJOlhuUeYbu/dvzAyjwBYCt2FBadPdkafz29IRZN2McfLXmCdizV6531TPh2H8Z/XA==,
}
cpu: [arm64]
os: [linux]
"@fallow-cli/linux-arm64-musl@2.73.0":
resolution:
{
integrity: sha512-rykM9ClOZ7cSUvox0Qesq3Vh4XTdHdgVDqgEo+njs1vJsj9IMINZhENsR7/9PKIEbH5rH/3BsOQ6wwkXwi7Z/w==,
}
cpu: [arm64]
os: [linux]
"@fallow-cli/linux-x64-gnu@2.73.0":
resolution:
{
integrity: sha512-BOk8LUgb97giUB5gUbH2PDV68EV/KlIKmNe+UyYeb8qsQkuIbwnYIxYQ1SmvagcCJdjkzGnJI4JXswvDB96MJg==,
}
cpu: [x64]
os: [linux]
"@fallow-cli/linux-x64-musl@2.73.0":
resolution:
{
integrity: sha512-zaHIF7rdNGj7gRJ49EG64nmuco1N074Na1DiOBn/bWg1YZxGlQlJL5d0cq1Kb+EoQ0sTwa+Ya4g4/mQ0Wdb+nA==,
}
cpu: [x64]
os: [linux]
"@fallow-cli/win32-arm64-msvc@2.73.0":
resolution:
{
integrity: sha512-IlWjJiSPY8j0n7jUEMNaEEdygwI4F2gzulAQmIcTlemZgdzAQCDuI3i8ylePcCc2+1YfD5IwdoQIS+WRkUulBw==,
}
cpu: [arm64]
os: [win32]
"@fallow-cli/win32-x64-msvc@2.73.0":
resolution:
{
integrity: sha512-pceEJAFpqmlp4gL+ANyhnNLFGtaHCydEaJCUFZ3TL885RWP2nvOIe4TbbdIGRJwAnw0aa6jtM8QKK0DNCSQlxQ==,
}
cpu: [x64]
os: [win32]
"@fastify/otel@0.18.0":
resolution:
{
@@ -8048,6 +8115,14 @@ packages:
}
engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 }
fallow@2.73.0:
resolution:
{
integrity: sha512-4qyUIGWhPvmeOnS6tNwB+WyVB92ImVWYEF6wiJT6Khn53SxIBi0+IxTsUT2NVjFR6mL4xRwL2vvpUe/OzvMYcw==,
}
engines: { node: ">=16" }
hasBin: true
fast-check@3.23.2:
resolution:
{
@@ -13574,6 +13649,30 @@ snapshots:
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
"@fallow-cli/darwin-arm64@2.73.0":
optional: true
"@fallow-cli/darwin-x64@2.73.0":
optional: true
"@fallow-cli/linux-arm64-gnu@2.73.0":
optional: true
"@fallow-cli/linux-arm64-musl@2.73.0":
optional: true
"@fallow-cli/linux-x64-gnu@2.73.0":
optional: true
"@fallow-cli/linux-x64-musl@2.73.0":
optional: true
"@fallow-cli/win32-arm64-msvc@2.73.0":
optional: true
"@fallow-cli/win32-x64-msvc@2.73.0":
optional: true
"@fastify/otel@0.18.0(@opentelemetry/api@1.9.1)":
dependencies:
"@opentelemetry/api": 1.9.1
@@ -17879,6 +17978,19 @@ snapshots:
jest-message-util: 29.7.0
jest-util: 29.7.0
fallow@2.73.0:
dependencies:
detect-libc: 2.1.2
optionalDependencies:
"@fallow-cli/darwin-arm64": 2.73.0
"@fallow-cli/darwin-x64": 2.73.0
"@fallow-cli/linux-arm64-gnu": 2.73.0
"@fallow-cli/linux-arm64-musl": 2.73.0
"@fallow-cli/linux-x64-gnu": 2.73.0
"@fallow-cli/linux-x64-musl": 2.73.0
"@fallow-cli/win32-arm64-msvc": 2.73.0
"@fallow-cli/win32-x64-msvc": 2.73.0
fast-check@3.23.2:
dependencies:
pure-rand: 6.1.0

View File

@@ -83,6 +83,17 @@
],
"outputs": []
},
"fallow": {
"inputs": [
"packages/**/src/**/*.ts",
"packages/**/src/**/*.tsx",
"apps/**/src/**/*.ts",
"apps/**/src/**/*.tsx",
"scripts/**/*.mjs",
".fallowrc.json"
],
"outputs": []
},
"build-storybook": {
"outputs": ["storybook-static/**"]
},