@tdk-landscape/tdk-cli-core 1.3.51 → 1.3.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.github/workflows/ci.yml +13 -0
  2. package/.github/workflows/release-binaries.yml +76 -1
  3. package/CHANGELOG.md +50 -0
  4. package/README.md +52 -17
  5. package/cli/README.md +16 -43
  6. package/cli/biome.json +0 -4
  7. package/cli/dist/commands/help.d.ts.map +1 -1
  8. package/cli/dist/commands/help.js +22 -39
  9. package/cli/dist/commands/help.js.map +1 -1
  10. package/cli/dist/commands/project.d.ts +6 -0
  11. package/cli/dist/commands/project.d.ts.map +1 -1
  12. package/cli/dist/commands/project.js +16 -0
  13. package/cli/dist/commands/project.js.map +1 -1
  14. package/cli/dist/commands/up.d.ts.map +1 -1
  15. package/cli/dist/commands/up.js +5 -0
  16. package/cli/dist/commands/up.js.map +1 -1
  17. package/cli/dist/commands/upgrade.d.ts +3 -0
  18. package/cli/dist/commands/upgrade.d.ts.map +1 -1
  19. package/cli/dist/commands/upgrade.js +43 -1
  20. package/cli/dist/commands/upgrade.js.map +1 -1
  21. package/cli/dist/utils/constants.d.ts +1 -1
  22. package/cli/dist/utils/constants.d.ts.map +1 -1
  23. package/cli/dist/utils/constants.js +1 -1
  24. package/cli/dist/utils/constants.js.map +1 -1
  25. package/cli/dist/utils/doctor-runtime.js +5 -5
  26. package/cli/dist/utils/doctor-runtime.js.map +1 -1
  27. package/cli/dist/utils/prompt.d.ts.map +1 -1
  28. package/cli/dist/utils/prompt.js +6 -1
  29. package/cli/dist/utils/prompt.js.map +1 -1
  30. package/cli/dist/utils/service-urls.js +1 -1
  31. package/cli/dist/utils/service-urls.js.map +1 -1
  32. package/cli/package.json +2 -1
  33. package/cli/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +2 -2
  34. package/cli/src/commands/__tests__/doctor.test.ts +8 -8
  35. package/cli/src/commands/__tests__/upgrade.test.ts +90 -3
  36. package/cli/src/commands/help.ts +22 -39
  37. package/cli/src/commands/project.ts +20 -0
  38. package/cli/src/commands/up.ts +10 -0
  39. package/cli/src/commands/upgrade.ts +52 -1
  40. package/cli/src/utils/constants.ts +1 -1
  41. package/cli/src/utils/doctor-runtime.ts +5 -5
  42. package/cli/src/utils/prompt.ts +8 -1
  43. package/cli/src/utils/service-urls.ts +1 -1
  44. package/discovery/identity-management-backend/service.yaml +2 -2
  45. package/discovery/identity-management-frontend/service.yaml +1 -1
  46. package/discovery/registry.star +3 -1
  47. package/discovery/services/platform/orchestrator/orchestrator-glue-backend/service.yaml +2 -2
  48. package/engine/assets/docker/golden-layers.Dockerfile +18 -18
  49. package/engine/assets/docker/wake-gateway/decide.test.ts +25 -0
  50. package/engine/assets/docker/wake-gateway/decide.ts +19 -0
  51. package/engine/assets/docker/wake-gateway/server.ts +60 -14
  52. package/engine/assets/scripts/mac-m1-resource-monitor.sh +1 -1
  53. package/engine/scripts/debug-container.sh +8 -3
  54. package/engine/spec.master +2 -2
  55. package/engine/topologies/platform/docker/layers/prisma/prisma_build.star +1 -1
  56. package/engine/topologies/tilt/common/utils.star +1 -1
  57. package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +53 -11
  58. package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +20 -0
  59. package/install.sh +19 -242
  60. package/openspec/changes/prioritized-cold-start/design.md +5 -1
  61. package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +9 -3
  62. package/openspec/changes/prioritized-cold-start/tasks.md +13 -0
  63. package/package.json +1 -1
  64. package/platform/services/platform/proxy/service.yaml +1 -1
  65. package/scripts/release-binaries.sh +8 -5
  66. package/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +2 -2
  67. package/tests/tilt-engine/test_sablier_defer_start.py +41 -0
  68. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/codebase-audit-report.md +0 -62
  69. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/.openspec.yaml +0 -5
  70. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/design.md +0 -94
  71. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/proposal.md +0 -46
  72. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CLEANUP_REPORT_8.md +0 -174
  73. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CRITICAL_ASSESSMENT_8.md +0 -160
  74. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/circular-deps/CRITICAL_ASSESSMENT_4.md +0 -381
  75. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/dead-code/CRITICAL_ASSESSMENT_3.md +0 -316
  76. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/CRITICAL_ASSESSMENT_1.md +0 -290
  77. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/IMPLEMENTATION_SUMMARY_1.md +0 -233
  78. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/defensive-cleanup/CRITICAL_ASSESSMENT_6.md +0 -835
  79. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/CRITICAL_ASSESSMENT_7.md +0 -254
  80. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/IMPLEMENTATION_SUMMARY_7.md +0 -187
  81. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/strong-typing/CRITICAL_ASSESSMENT_5.md +0 -269
  82. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/CRITICAL_ASSESSMENT_2.md +0 -312
  83. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/IMPLEMENTATION_SUMMARY.md +0 -170
  84. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/tasks.md +0 -137
package/install.sh CHANGED
@@ -1,242 +1,19 @@
1
- #!/bin/bash
2
- # TDK CLI Install Script
3
- # Install the Tilt Development Kit CLI
4
- # Usage: curl -fsSL https://raw.githubusercontent.com/tdk-landscape/tdk-cli-core/main/install.sh | bash
5
-
6
- set -e
7
-
8
- # Colors
9
- RED='\033[0;31m'
10
- GREEN='\033[0;32m'
11
- YELLOW='\033[1;33m'
12
- BLUE='\033[0;34m'
13
- NC='\033[0m' # No Color
14
-
15
- # Configuration
16
- REPO_URL="https://github.com/tdk-landscape/tdk-cli-core.git"
17
- INSTALL_DIR="${HOME}/.tdk"
18
- BIN_DIR="${HOME}/.bun/bin"
19
-
20
- # Print functions
21
- print_info() {
22
- echo -e "${BLUE}ℹ️ $1${NC}"
23
- }
24
-
25
- print_success() {
26
- echo -e "${GREEN}✅ $1${NC}"
27
- }
28
-
29
- print_warning() {
30
- echo -e "${YELLOW}⚠️ $1${NC}"
31
- }
32
-
33
- print_error() {
34
- echo -e "${RED}❌ $1${NC}"
35
- }
36
-
37
- # Check if command exists
38
- command_exists() {
39
- command -v "$1" >/dev/null 2>&1
40
- }
41
-
42
- # Detect OS
43
- detect_os() {
44
- case "$(uname -s)" in
45
- Linux*) echo "linux";;
46
- Darwin*) echo "macos";;
47
- CYGWIN*) echo "windows";;
48
- MINGW*) echo "windows";;
49
- MSYS*) echo "windows";;
50
- *) echo "unknown";;
51
- esac
52
- }
53
-
54
- # Check prerequisites
55
- check_prerequisites() {
56
- print_info "Checking prerequisites..."
57
-
58
- OS=$(detect_os)
59
- print_info "Detected OS: $OS"
60
-
61
- # Check for git
62
- if ! command_exists git; then
63
- print_error "git is required but not installed."
64
- echo "Please install git first:"
65
- echo " macOS: brew install git"
66
- echo " Linux: sudo apt-get install git (or your package manager)"
67
- exit 1
68
- fi
69
-
70
- # Check for a JavaScript runtime (bun or node)
71
- if command_exists bun; then
72
- RUNTIME="bun"
73
- print_success "Found bun runtime"
74
- elif command_exists node; then
75
- RUNTIME="node"
76
- print_success "Found node runtime"
77
-
78
- # Check for npm
79
- if ! command_exists npm; then
80
- print_error "npm is required with node but not found"
81
- exit 1
82
- fi
83
- else
84
- print_warning "No JavaScript runtime found (bun or node)"
85
- echo ""
86
- echo "Would you like to install Bun? (Recommended - much faster)"
87
- echo " curl -fsSL https://bun.sh/install | bash"
88
- echo ""
89
- read -p "Install Bun now? [Y/n] " -n 1 -r
90
- echo
91
- if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then
92
- print_info "Installing Bun..."
93
- curl -fsSL https://bun.sh/install | bash
94
-
95
- # Source bun setup
96
- if [ -f "${HOME}/.bashrc" ]; then
97
- export BUN_INSTALL="${HOME}/.bun"
98
- export PATH="${BUN_INSTALL}/bin:$PATH"
99
- fi
100
-
101
- if command_exists bun; then
102
- RUNTIME="bun"
103
- print_success "Bun installed successfully"
104
- else
105
- print_error "Bun installation failed or not in PATH"
106
- print_info "Please restart your terminal and run this script again"
107
- exit 1
108
- fi
109
- else
110
- print_error "Bun or Node.js is required to install TDK"
111
- exit 1
112
- fi
113
- fi
114
- }
115
-
116
- # Setup directories
117
- setup_directories() {
118
- print_info "Setting up directories..."
119
-
120
- mkdir -p "$INSTALL_DIR"
121
- mkdir -p "$BIN_DIR"
122
-
123
- print_success "Directories created"
124
- }
125
-
126
- # Clone or update repository
127
- clone_repository() {
128
- print_info "Cloning TDK CLI repository..."
129
-
130
- if [ -d "${INSTALL_DIR}/tdk-cli" ]; then
131
- print_warning "Existing installation found, updating..."
132
- cd "${INSTALL_DIR}/tdk-cli"
133
- git fetch origin
134
- git reset --hard origin/main
135
- else
136
- git clone --depth 1 "$REPO_URL" "${INSTALL_DIR}/tdk-cli"
137
- cd "${INSTALL_DIR}/tdk-cli"
138
- fi
139
-
140
- print_success "Repository cloned/updated"
141
- }
142
-
143
- # Install dependencies and link
144
- install_and_link() {
145
- print_info "Installing dependencies..."
146
-
147
- cd "${INSTALL_DIR}/tdk-cli/cli"
148
-
149
- if [ "$RUNTIME" = "bun" ]; then
150
- bun install
151
- print_success "Dependencies installed with bun"
152
-
153
- print_info "Linking TDK CLI..."
154
- bun link --force
155
- print_success "TDK CLI linked globally"
156
- else
157
- npm install
158
- print_success "Dependencies installed with npm"
159
-
160
- print_info "Linking TDK CLI..."
161
- npm link --force
162
- print_success "TDK CLI linked globally"
163
- fi
164
- }
165
-
166
- # Setup PATH
167
- setup_path() {
168
- print_info "Setting up PATH..."
169
-
170
- SHELL_CONFIG=""
171
- if [ -f "${HOME}/.zshrc" ]; then
172
- SHELL_CONFIG="${HOME}/.zshrc"
173
- elif [ -f "${HOME}/.bashrc" ]; then
174
- SHELL_CONFIG="${HOME}/.bashrc"
175
- elif [ -f "${HOME}/.bash_profile" ]; then
176
- SHELL_CONFIG="${HOME}/.bash_profile"
177
- fi
178
-
179
- if [ -n "$SHELL_CONFIG" ]; then
180
- if ! grep -q "\.bun/bin" "$SHELL_CONFIG" 2>/dev/null; then
181
- echo "" >> "$SHELL_CONFIG"
182
- echo "# TDK CLI (installed via install.sh)" >> "$SHELL_CONFIG"
183
- echo 'export PATH="${HOME}/.bun/bin:${PATH}"' >> "$SHELL_CONFIG"
184
- print_success "Added ~/.bun/bin to PATH in $(basename "$SHELL_CONFIG")"
185
- print_warning "Please restart your terminal or run: source $SHELL_CONFIG"
186
- else
187
- print_info "PATH already configured in $(basename "$SHELL_CONFIG")"
188
- fi
189
- else
190
- print_warning "Could not detect shell config file"
191
- print_info "Please manually add to your shell config:"
192
- echo 'export PATH="${HOME}/.bun/bin:${PATH}"'
193
- fi
194
- }
195
-
196
- # Verify installation
197
- verify_installation() {
198
- print_info "Verifying installation..."
199
-
200
- export PATH="${BIN_DIR}:${PATH}"
201
-
202
- if command_exists tdk; then
203
- VERSION=$(tdk -v 2>/dev/null || echo "unknown")
204
- print_success "TDK CLI installed successfully!"
205
- echo ""
206
- echo "Version: $VERSION"
207
- echo "Location: $(which tdk)"
208
- echo ""
209
- echo "Quick start:"
210
- echo " tdk --help # Show all commands"
211
- echo " tdk project # Initialize a new project"
212
- echo " tdk resource api # Create a new resource"
213
- echo ""
214
- print_info "Happy coding! 🚀"
215
- else
216
- print_error "Installation verification failed"
217
- print_info "tdk command not found in PATH"
218
- print_info "You may need to restart your terminal or run:"
219
- echo " export PATH=\"${HOME}/.bun/bin:\${PATH}\""
220
- exit 1
221
- fi
222
- }
223
-
224
- # Main installation flow
225
- main() {
226
- echo ""
227
- echo "╔════════════════════════════════════════════════════════════╗"
228
- echo "║ 🚀 TDK CLI Installer ║"
229
- echo "║ Tilt Development Kit - Install Script ║"
230
- echo "╚════════════════════════════════════════════════════════════╝"
231
- echo ""
232
-
233
- check_prerequisites
234
- setup_directories
235
- clone_repository
236
- install_and_link
237
- setup_path
238
- verify_installation
239
- }
240
-
241
- # Run main function
242
- main "$@"
1
+ #!/usr/bin/env bash
2
+ # Legacy installer URL for the TDK CLI.
3
+ #
4
+ # The official installer is https://tdk-landscape.github.io/install.sh. It
5
+ # installs the prebuilt `tdk` binary plus its bundled engine, verified
6
+ # against the release checksums, with no Node or Bun required. This script
7
+ # used to clone this repo and `bun link` it instead; it now hands off to the
8
+ # official installer so old
9
+ # curl -fsSL https://raw.githubusercontent.com/tdk-landscape/tdk-cli-core/main/install.sh | bash
10
+ # commands keep working and every install method gets the same result.
11
+ #
12
+ # To work on TDK itself, clone the repo instead (see CONTRIBUTING.md).
13
+
14
+ set -euo pipefail
15
+
16
+ readonly OFFICIAL_INSTALLER="https://tdk-landscape.github.io/install.sh"
17
+
18
+ echo "Using the official TDK installer: ${OFFICIAL_INSTALLER}" >&2
19
+ curl -fsSL "${OFFICIAL_INSTALLER}" | sh
@@ -35,6 +35,8 @@ See `proposal.md` (Why) for the motivating case. Relevant current behavior:
35
35
 
36
36
  Add a `deferStart` key to the manifest's existing `sablier` block (`engine/topologies/tilt/manifest/schema.star`'s `sablier` schema, alongside `enable`/`group`/`sessionDuration`), default `false`. `_register_replicas` (and any other call site that currently receives the single `auto_init_apps` flag for app resources) resolves per-resource auto-init as `auto_init_apps and not resource_defers_start(manifest)` instead of using `auto_init_apps` directly. The resource's **config-gen** and **docker_build** resources keep `auto_init=True` unconditionally (or follow `auto_init_config_gen`, already `True` by default) so the image still builds during `tdk up` — only the running container is held back.
37
37
 
38
+ **Corrected live (2026-09-27, task 7.2/7.7):** that last sentence assumed wrongly. In this codebase `docker_build` has no `auto_init` of its own: Tilt attaches the image target to the `dc_resource` that deploys it, so `auto_init=False` skips the image build too. A `tdk up` on `tdk-erp-system` recorded zero builds for the deferred `data-governance-api`. **Fix:** each `deferStart` resource also gets a `<name>-image` `local_resource` (auto-init follows the landscape-wide `auto_init_apps`, not the deferred flag) that runs `docker build --target production --network host` into the tag the compose service declares. A plain `docker build` has no `only=` filter, so it builds from a copy of the Dockerfile (`<Dockerfile>.prebuild`) whose Dockerfile-specific `.dockerignore` is an allowlist generated from the same `only=`/`ignore=` lists `docker_build` uses (`TypescriptBuilders.prebuild_dockerignore`). Verified on `data-governance-api`: 14 kB build context, every layer served from the cache Tilt's own build populated, and filesystem layers identical to Tilt's image (only Tilt's `dev.tilt.*` labels differ). Tilt's own `docker_build` stays registered, so the first `tilt trigger` still gets live update.
39
+
38
40
  *Alternatives considered:*
39
41
  - A separate global "cold landscape" mode (e.g. `TILT_DEFER_ALL_APPS`): rejected because it can't express "just this one resource," which is the actual request (one API, not the whole landscape).
40
42
  - Piggybacking on `TILT_TRIGGER_MODE=manual` wholesale: rejected — that already exists and disables `enforce_migrator_deps` and replica counts landscape-wide; overloading it would change unrelated behavior for every resource, not just opted-in ones.
@@ -67,7 +69,9 @@ Either way, the gateway is the single thing the static route (D4) points at, and
67
69
  - Confirmed live: the Tilt/Compose *resource* name (what `tilt trigger` and Compose's own `depends_on` use) is not the same string as the Docker *container* name Compose actually creates (`<project>-<service>-1`, e.g. `analytics-autogenerated-data-governance-api-1` for resource `data-governance-api`) — `docker inspect` needs the latter. The gateway and the generated route both carry both identifiers (`X-Wake-Resource` / `X-Wake-Container`) rather than assuming they're interchangeable.
68
70
  - A full disposable rehearsal (isolated Tilt + Docker Compose + the built gateway image, torn down after) woke a cold `traefik/whoami` container from both "exited" and fully "absent" states and correctly proxied a request through with its original path intact.
69
71
 
70
- **In progress, live against `tdk-erp-system` (2026-09-27):** the queue-bypass fix above (direct `docker compose up --no-build`) is implemented, unit/Starlark-tested (`decide.test.ts`'s new compose-start cases, `test_traefik_static_wake_route.py`'s new compose-invocation case, `test_standalone_traefik.py`'s new project-mount case — all passing), re-vendored into the live project, and the generated route now carries the `X-Wake-Compose-*`/`X-Wake-Image` headers. Still waiting on Tilt to actually rebuild the `wake-gateway`/`traefik` resources with this change under the same landscape-wide build-queue contention that motivated the fix in the first place — task 7.2 records the final result once that rebuild completes and the original cold-start URL is re-tested.
72
+ **Verified live against `tdk-erp-system` (2026-09-27):** with the landscape quiet, the original URL answered `200` from a fully cold container in 19.2s via the direct compose start (task 7.2).
73
+
74
+ **Early `503` + `Retry-After` (task 7.8):** during a full `tdk up` bring-up the Docker daemon itself was the bottleneck: the direct start took ~5 min, and Bun's 255s idle cap dropped the held request with no response at all. Holding the request longer can't fix a saturated daemon, so the gateway now holds a waking request for at most 60s (`EARLY_RESPONSE_MS`, overridable via `X-Wake-Respond-Within-Ms`, capped at 240s), then answers `503` with `Retry-After: 10` while the start continues in the background. One wake runs per resource at a time: a retry, or another caller arriving meanwhile, joins the wake in progress rather than starting the container again. A resource that becomes healthy within the window is still answered directly, so the quiet-landscape case is unchanged.
71
75
 
72
76
  ### D4: A never-created resource's route comes from Traefik's static/file provider, not Docker-label discovery
73
77
 
@@ -13,7 +13,7 @@ A resource with a `sablier` manifest block SHALL be able to mark itself deferred
13
13
  #### Scenario: Deferred resource is not started during tdk up
14
14
 
15
15
  - **WHEN** `tdk up` runs a landscape containing a resource with deferred start enabled
16
- - **THEN** that resource's image build completes during the run
16
+ - **THEN** that resource's image build completes during the run, under the image tag its compose service declares, so its first request can start it without building
17
17
  - **AND** the resource's container is not started, and `tdk up` does not wait on it to become healthy before finishing bring-up of the rest of the landscape
18
18
 
19
19
  #### Scenario: Non-opted-in resource is unaffected
@@ -65,13 +65,19 @@ Waking a deferred resource SHALL also wake any of its required startup dependenc
65
65
 
66
66
  ### Requirement: A Waking Request Waits For Health, Not Just Start
67
67
 
68
- A request that triggers a deferred resource's startup SHALL be held until the resource passes its health check or until a bounded timeout elapses, rather than being answered as soon as the container process starts.
68
+ A request that triggers a deferred resource's startup SHALL be held until the resource passes its health check, until a bounded hold window elapses, or until a bounded timeout elapses, rather than being answered as soon as the container process starts. The caller SHALL always receive a response; the connection SHALL NOT be dropped silently.
69
69
 
70
70
  #### Scenario: Client receives the real response
71
71
 
72
- - **WHEN** a request wakes a deferred resource
72
+ - **WHEN** a request wakes a deferred resource that becomes healthy within the hold window
73
73
  - **THEN** the client's request is held and then answered by the resource once it is healthy, rather than receiving an immediate "starting" response with no real answer
74
74
 
75
+ #### Scenario: Startup outlasts the hold window
76
+
77
+ - **WHEN** a request wakes a deferred resource that is still not healthy when the hold window ends (e.g. the Docker daemon is saturated by a full `tdk up` bring-up)
78
+ - **THEN** the request is answered with `503` and a `Retry-After` header while the start continues in the background
79
+ - **AND** a retry, or any other request that arrives meanwhile, joins that same start instead of starting the resource again, and is answered by the resource once it is healthy
80
+
75
81
  #### Scenario: Startup exceeds the timeout
76
82
 
77
83
  - **WHEN** a deferred resource does not become healthy within its configured wake timeout
@@ -46,6 +46,15 @@
46
46
  - Added the `sablier` block to `data-governance-api/service.json`, re-vendored, and confirmed the generated route (`traefik-dynamic/data-governance-api.yml`) and cold behavior (no container until first request) all work as designed.
47
47
  - First real pass found and fixed two genuine bugs (not environment noise): (a) task 7.4's queue-bypass fix (`tilt trigger` alone queued behind Tilt's build-slot cap and 504'd — see D3); (b) after that fix, a second real bug — the app only serves its bare health path (`/health`), and the generated wake route forwarded the full public path (`/api/data-governance/health`) unstripped, unlike the real Docker-label `-project` router, so a successful wake still 404'd. Fixed by adding a matching `stripPrefix` middleware to the generated route (`traefik_static_routes.star`), reusing the same `cli_api_path()` the Docker-label router strips with. Both fixes are unit/Starlark-tested (33/33 passing) and re-vendored into the live project.
48
48
  - **Re-test after both fixes is inconclusive, not failing**: a `docker rm -f` + cold curl got a `502` from Traefik itself (not the gateway's own 504), and the gateway's log showed only its initial "wake" decision line, never a "compose start ... started/failed" result — `docker compose up` inside the gateway appears to have stalled rather than erred. Root-caused to the machine, not the code: `tilt get uiresource` showed **104 of 250 resources still `pending`**, mid a mass rebuild (Tilt's build-slot cap processing 3 at a time) triggered by this task's own repeated `tdk project --yes` + forced-Tiltfile-re-eval cycles across this session — sustained load average ~26-27, `docker ps`/`traefik ping` themselves taking 10-30s, and Traefik logged a stale `data-governance-api@docker` service IP getting "no route to host" consistent with a container that started to come up and was torn down mid-flight under this contention. **Decision (2026-09-27, developer's own call, not further probed by any session)**: stop touching the live landscape rather than keep polling an already-overloaded daemon (load average climbed to ~38 after this note was first written, queue hadn't drained) or force a Docker Desktop restart that would kill the ~110 containers of a 14+-hour-running landscape. The code changes (task 7.4's queue-bypass fix and this task's strip-prefix fix) ship as-is on the strength of their unit/Starlark tests (33/33 passing) plus the one clean live pass that *did* complete end-to-end before the path-stripping bug was found (container created from cold via direct compose start, no Tilt-queue wait, "compose start data-governance-api: started" logged, and a genuine 502→200 progression as each bug was fixed in turn) — not on an unattainable final green run under a saturated host. This task stays open (checkbox unchecked) rather than being marked done on inference: the one remaining step is a single clean re-run of `curl http://api.tdk-erp-system.localhost/api/data-governance/health` against a quiescent `tdk-erp-system` landscape, entirely at the developer's own convenience, with no further re-vendor/re-eval cycles needed first (the fixes are already vendored in).
49
+ - **Live re-test passed, 2026-09-27 18:55** (landscape quiet: Tilt no longer running, load ~17, no re-vendor/re-eval needed): warm `curl http://api.tdk-erp-system.localhost/api/data-governance/health` → `200` with the real health body in 0.6s (the same request 404'd before task 7.5's strip-prefix fix). Then `docker rm -f` the container, confirmed absent, same `curl` → **`200` `{"status":"healthy",...}` in 19.2s** from fully cold. Gateway log: `wake data-governance-api: state=absent compose=true trigger=[]` → `compose start data-governance-api: started` — task 7.4's direct-start path, no Tilt involvement at all (Tilt was not even running). This closes the proposal's motivating gap on the real landscape. Side observation: Traefik's own Docker-label routers for this resource are `disabled` because the Sablier Traefik plugin fails its integrity check on download (`plugin integrity check failed`, plugins disabled), so every request currently goes through the wake route — a separate, pre-existing plugin-download problem, not part of this change.
50
+ - **Still unverified live (why the box stays unchecked):** the two parts of 7.2 that need Tilt itself running — (a) task 3.3, that a fresh `tdk up` leaves `data-governance-api` with no container until its first request, and (b) that `tdk doctor` reports it as deferred rather than stalled. Both are covered by unit tests (3.1/3.2 predicate tests, 6.2's doctor tests) but not yet observed on this landscape. Next step: one `tdk up` in `tdk-erp-system`, then `docker ps -a --filter name=data-governance-api` (expect nothing) and `tdk doctor`.
51
+ - **`tdk up` run, 2026-09-27 19:08 (global `tdk` 1.3.51, premium overlay in place, container removed first):**
52
+ - ✅ `tdk up`'s summary printed `data-governance-api: .../api/data-governance/health (deferred — starts on first request)` (task 6.1, live).
53
+ - ✅ After the Tiltfile evaluated, Tilt left `data-governance-api` at `updateStatus: none` / `runtimeStatus: none` and created no container (task 3.3's container half, live).
54
+ - ❌ **Image not built.** Contrary to the design comment in `_register_single_resource` and the spec's "Deferred Start Opt-In" requirement, `auto_init=False` skips the resource's image build as well as its container: this Tilt session recorded zero builds for `data-governance-api`, and its newest image predates the session. The image only existed because earlier sessions built it. On a fresh project the first wake finds no image, `ensureImage()` fails, and the gateway falls back to `tilt trigger` — the queueing path task 7.4 was meant to avoid.
55
+ - ❌ **Cold wake during a full bring-up timed out for the caller.** Hit the URL at 19:10:42 with 134 resources pending: the gateway chose the direct compose path (`state=absent compose=true`), but `docker image inspect` took ~2 min and `docker compose up` ~3 min more because the Docker daemon itself was saturated by the bring-up (`tdk doctor` also aborted: `docker ps` hung >10s). The container started at 19:15:36 (~5 min), after Bun's 255s idle timeout had already dropped the client connection (`HTTP 000`). A follow-up request returned `200` in 16s. So bypassing Tilt's build queue works, but under a full bring-up the Docker daemon is the next bottleneck, and the gateway gives the caller no response in that case.
56
+ - ⏸ `tdk doctor`'s deferred reporting (6.2) not observed yet: doctor exits at its Docker-responsiveness check while the daemon is this loaded.
57
+ - **Open decisions, resolved by the developer 2026-09-27:** (1) build the image during `tdk up` → task 7.7; (2) answer slow wakes with an early `503` + `Retry-After` → task 7.8. Both implemented and tested; neither re-vendored into `tdk-erp-system` yet. **What remains for this task:** re-vendor, then one `tdk up` to confirm the `data-governance-api-image` resource builds and the container stays absent, a cold request during bring-up to confirm a `503` + `Retry-After` followed by a successful retry, and `tdk doctor` once the Docker daemon is responsive enough for its 10s check.
49
58
  - **2026-09-27 disposable probe (torn down after, nothing kept):** to verify task 7.3's fix end-to-end rather than only at the Starlark-unit level, stood up an isolated Tilt + Docker Compose project (two `traefik/whoami` services, `dep-service` and `primary-service`, both `dc_resource(auto_init=False)`) plus a standalone Traefik with the file provider enabled. Generated `primary-service`'s static route with the **real, unmodified** `generate_static_wake_route()` from `traefik_static_routes.star`, passing `dependencies=[("dep-service", "wakeprobe")]` the same shape `resolve_defer_start_dependencies` now produces — confirmed the emitted YAML carries `X-Wake-Deps: "dep-service=wakeprobe-dep-service-1"`. Ran the real `wake-gateway/server.ts` (as a local Bun process against this container's own Tilt daemon and Docker socket, since building the packaged Docker image failed here on an unrelated Alpine/`apk` proxy TLS issue — the packaged image itself is unaffected, this only affected building it ad hoc in this sandbox). A single HTTP request against `primary-service`'s route, while both containers were confirmed absent beforehand, resulted in **both** `wakeprobe-primary-service-1` and `wakeprobe-dep-service-1` being created and started (verified via `docker ps` and `tilt logs` showing both `tilt trigger` calls succeed) — this is the exact behavior task 7.3 added and that D5's requirement describes, now observed working end-to-end, not just unit-tested. The final proxy-through step returned a connection error, but only because the gateway ran as a host process outside the Compose network and so couldn't resolve the container's Compose-DNS name (`primary-service`) — confirmed by curling the container's bridge IP directly and getting a real `200`; that proxy-through mechanic itself was already verified live in task 4.3's own probe when the gateway ran inside the correct Docker network, and is unrelated to 7.3's change. One real, unrelated hiccup along the way: `primary-service`'s first `tilt trigger` failed with a Docker Hub `429 Too Many Requests` on the image pull (transient registry throttling, not a bug); a second trigger with the image already cached succeeded normally.
50
59
  - [x] 7.3 (Found 2026-09-26 re-reading the shipped code) Wire real dependency data into the `generate_static_wake_route(...)` call at `apply_compose_resource_registration.star:442` — it always passed no `dependencies=` argument, so every generated route shipped `X-Wake-Deps: ""` despite the gateway side and the generator's `dependencies` param both being implemented and unit-tested in isolation. **Done, 2026-09-26**: added `resolve_manifest_dependency_names(manifest, all_services_map)` (reuses the existing `_resolve_dependency_to_resource` that `_build_resource_deps` already trusts for Tilt's own `resource_deps` ordering — an ambiguous name behaves identically here as it already does there) and `resolve_defer_start_dependencies(manifest, resource_manifests, all_services_map)` (filters those resolved names to the ones whose own manifest is itself `resource_defers_start`), both in `apply_compose_resource_registration.star`, no leading underscore so they're directly `load()`-able for tests per task 3.1's precedent. The call site now passes `dependencies=resolve_defer_start_dependencies(manifest, resource_manifests, all_services_map)`. 6 new cases in `test_sablier_defer_start.py` cover: exact-name resolution, an unresolvable name falling back to exclusion (not a guess), a dependency that resolves but isn't itself deferStart, and the free-tier license gate keeping the result empty even for a `dependsOn` target whose manifest asks for `deferStart` (mirrors task 3.1's own license-gate tests, since `resource_defers_start` is reused unchanged) — full 166/166 passing (166 = prior 160 + these 6; the pre-existing 29 unrelated failures in `tests/tilt-engine/` — `test_agents_md_*`, `test_daemon_*`, `test_snapshot_scanning`, etc. — are identical before and after this change, confirmed by diffing the failure list against a `git stash` baseline). The "licensed and actually wakes a peer deferStart resource" end-to-end case still can't be exercised from this repo's free-tier stub, same limitation task 3.1 already documented — folded into task 7.2's live run rather than duplicated here.
51
60
 
@@ -53,4 +62,8 @@
53
62
 
54
63
  - [x] 7.6 Benchmark task 7.4's queue-bypass fix with real, reproducible numbers rather than relying solely on the one interrupted live pass. **Done, 2026-09-27**: a disposable, isolated benchmark (own Tilt instance on a private port, own Compose project, torn down completely after — no interaction with any real project) exercising the actual shipped `generate_static_wake_route()`/`decide.ts`/`server.ts` code against a genuine build-slot queue (`max_parallel_updates=2`, six slow-building filler resources). Full setup, results table, and interpretation recorded in `design.md`'s new "Benchmark: D3's queue-bypass fix, measured" section. Headline results: the new direct-start path (`target-fast`) answered in 7.4-12.6s regardless of whether the build queue was saturated; the old `tilt trigger`-only fallback (`target-slow`) cost 18.1-22.8s even at its best (idle) case, confirmed via Tilt's own build history to be paying its build-reconciliation step unconditionally — the same step that queues behind other builds and caused the original live `504`.
55
64
 
65
+ - [x] 7.7 (Found live, task 7.2's `tdk up` run, 2026-09-27) Build a deferred resource's image during `tdk up`: `auto_init=False` also skipped its `docker_build`, contrary to D1's original assumption. **Done** (`3f25fe6`): `_register_deferred_image_prebuild` adds a `<name>-image` `local_resource` per `deferStart` resource that builds the same image under the compose-declared tag, using a Dockerfile copy with an allowlist `.dockerignore` from the new `TypescriptBuilders.prebuild_dockerignore` (mirrors `docker_build`'s `only=`/`ignore=`). New `test_prebuild_dockerignore_mirrors_docker_build_only_and_ignore` case; 35/35 related Starlark tests pass. Verified by hand on `data-governance-api` with the exact command the resource runs (throwaway tag): 14 kB context, all layers cached, filesystem layers identical to Tilt's image.
66
+
67
+ - [x] 7.8 (Found live, task 7.2's `tdk up` run, 2026-09-27) Never drop a waking request silently. **Done** (`3f25fe6`): `server.ts` holds for `earlyResponseMs()` (60s default, `X-Wake-Respond-Within-Ms` override capped at 240s under Bun's 255s idle limit), then answers `503` + `Retry-After: 10` while the start continues; an in-flight map keeps one wake per resource so retries join it. Spec updated ("Startup outlasts the hold window" scenario). 18/18 `bun test` cases pass (4 new for the timing rules); `server.ts`/`decide.ts` type-check under `strict` with Bun types. Not yet exercised live: the in-flight join and the 503 path need a slow start to observe (task 7.2's remaining step).
68
+
56
69
  - [x] 7.4 (Found live during task 7.2's real `tdk-erp-system` run, 2026-09-27) `tilt trigger`-only wake failed under real load: with ~100+ resources mid-rebuild after a re-vendor (Tilt caps concurrent builds at a handful of slots), a triggered `deferStart` resource sat queued behind them and the request timed out with a `504` — the exact "wait behind a huge landscape" problem this feature exists to remove, just relocated to Tilt's build queue. **Done**: the gateway now prefers creating/starting the resource directly with `docker compose up -d --no-build <resource>` (the same command Tilt's own `<resource>-run-only` local_resource runs) whenever the generated route supplies the resource's compose invocation, falling back to `tilt trigger` only when no image has ever been built for it yet (`ensureImage()` first tries retagging Tilt's own `<repo>:tilt-<hash>` build as `<repo>:dev` in case the plain tag was never created). Changes: `decide.ts`'s `decideWakeAction` gained `useComposeStart`/`hasComposeInvocation` and `wakeTimeoutMs()` (180s for a direct start, 240s when a build might be needed, under Bun's 255s idle cap) with new `decide.test.ts` cases; `server.ts` gained `composeStart()`/`ensureImage()` and reads `X-Wake-Compose-Project`/`X-Wake-Compose-Files`/`X-Wake-Env-File`/`X-Wake-Image`; `traefik_static_routes.star`'s `generate_static_wake_route` gained matching optional params/headers (new `test_static_route_carries_compose_invocation_for_direct_start` case) plus a `normalize_abs_path()` helper (Tilt's `os.path.abspath` doesn't collapse `..`, and the generated Tiltfile's project root is exactly `config.main_dir + "/../.."` — confirmed with a throwaway probe, new `test_normalize_abs_path_collapses_dot_segments` case); `apply_compose_resource_registration.star` gained `_wake_compose_invocation()` wiring the resource's actual compose files/env/image into the call site; `traefik_standalone.star` mounts the project root read-only into the gateway container at the same normalized absolute path so those compose files resolve identically there (new `test_wake_gateway_mounts_project_root_at_its_own_absolute_path` case). Dockerfile gained `docker-cli-compose`. 33/33 Starlark tests and the full `bun test` suite (25 assertions) pass. Live re-verification against `tdk-erp-system` (re-vendored, route regenerated with the new headers, gateway/Traefik rebuild in progress under the same real build-queue contention that motivated this) folded into 7.2's final result below rather than duplicated here.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tdk-landscape/tdk-cli-core",
3
- "version": "1.3.51",
3
+ "version": "1.3.52",
4
4
  "description": "Run 100 microservices on a 16 GB laptop without Kubernetes. Scaffold services and run them locally with hot reload, built on Tilt.",
5
5
  "homepage": "https://tdk-landscape.github.io/tdk-website",
6
6
  "repository": {
@@ -10,5 +10,5 @@ dependsOn:
10
10
  - database-management
11
11
  runtime: docker
12
12
  traefik:
13
- host: traefik.beauty-crm.localhost
13
+ host: traefik.tdk-project.localhost
14
14
  pathPrefix: /dashboard
@@ -45,14 +45,17 @@ cp -R "${ROOT_DIR}/cli/templates" "${RELEASE_DIR}/tdk-cli/cli/templates"
45
45
 
46
46
  (
47
47
  cd "${RELEASE_DIR}"
48
- shasum -a 256 tdk-linux-amd64 tdk-linux-arm64 tdk-darwin-amd64 tdk-darwin-arm64 > checksums.txt
49
- zip -qr "tdk-cli-${RELEASE_TAG}-binaries.zip" \
50
- tdk-linux-amd64 tdk-linux-arm64 tdk-darwin-amd64 tdk-darwin-arm64 \
51
- tdk-cli checksums.txt
52
48
  # Fixed filename (no version/tag in the name) so install.sh can always
53
49
  # find it via the stable /releases/latest/download/ URL, unlike the zip
54
- # above whose name embeds the tag and changes every release.
50
+ # below whose name embeds the tag and changes every release.
55
51
  tar -czf tdk-cli-engine.tar.gz tdk-cli
52
+ # install.sh and `tdk upgrade` verify the binary and the engine tarball
53
+ # against this file before installing them.
54
+ shasum -a 256 tdk-linux-amd64 tdk-linux-arm64 tdk-darwin-amd64 tdk-darwin-arm64 \
55
+ tdk-cli-engine.tar.gz > checksums.txt
56
+ zip -qr "tdk-cli-${RELEASE_TAG}-binaries.zip" \
57
+ tdk-linux-amd64 tdk-linux-arm64 tdk-darwin-amd64 tdk-darwin-arm64 \
58
+ tdk-cli checksums.txt
56
59
  )
57
60
 
58
61
  echo "Built release assets in ${RELEASE_DIR}"
@@ -86,7 +86,7 @@ DB_WAIT_INTERVAL="${DB_WAIT_INTERVAL:-2}"
86
86
  # =============================================================================
87
87
  #
88
88
  # Problem: Tilt creates databases but doesn't know what Infisical contains.
89
- # This causes DATABASE_URL mismatch (e.g., beauty_crm_staff vs staff_db_prod)
89
+ # This causes DATABASE_URL mismatch (e.g., tdk_project_staff vs staff_db_prod)
90
90
  #
91
91
  # Solution: TILT_* prefixed variables ALWAYS override Infisical secrets
92
92
  # Tilt sets TILT_DATABASE_URL → we export it as DATABASE_URL BEFORE infisical run
@@ -151,7 +151,7 @@ wait_for_postgres() {
151
151
 
152
152
  # If we have psql, do a deeper health check
153
153
  if command -v psql >/dev/null 2>&1; then
154
- if PGPASSWORD="${db_password:-}" psql -h "${db_host}" -p "${db_port}" -U "${db_user:-beauty_crm}" -d "${db_name}" -c "SELECT 1" >/dev/null 2>&1; then
154
+ if PGPASSWORD="${db_password:-}" psql -h "${db_host}" -p "${db_port}" -U "${db_user:-tdk_project}" -d "${db_name}" -c "SELECT 1" >/dev/null 2>&1; then
155
155
  log_success "✅ Database ${db_name} is ready!"
156
156
  return 0
157
157
  fi
@@ -191,6 +191,47 @@ def test_resolve_manifest_dependency_names_exact_match(tmp_path):
191
191
  assert _run_resolve_names(tmp_path, manifest, all_services_map) == ["identity-management-backend"]
192
192
 
193
193
 
194
+ def test_prebuild_dockerignore_mirrors_docker_build_only_and_ignore(tmp_path):
195
+ """A deferStart resource's image is pre-built by a plain `docker build`
196
+ (auto_init=False skips the dc_resource's own docker_build -- found live,
197
+ task 7.2). A plain build has no only= filter, so the generated allowlist
198
+ must include exactly what docker_build's only= does (root lockfiles, the
199
+ service, docker-templates, its internal libraries) and re-exclude its
200
+ ignore= patterns, or the whole project root becomes the build context."""
201
+ project = tmp_path / "project"
202
+ service = project / "services" / "analytics" / "data-governance-api"
203
+ (service / ".autogenerated").mkdir(parents=True)
204
+ (service / "package.json").write_text(
205
+ json.dumps({"dependencies": {"@tdk-project/platform-logging": "workspace:*", "zod": "^3"}})
206
+ )
207
+ dockerfile = service / ".autogenerated" / "Dockerfile.app.autogenerated"
208
+ dockerfile.write_text("FROM scratch\n")
209
+ (service / ".autogenerated" / "Dockerfile.app.autogenerated.dockerignore").write_text(
210
+ "# comment\nnode_modules\n*.md\n!.env.example\n"
211
+ )
212
+ tiltdir = tmp_path / "tilt"
213
+ tiltdir.mkdir()
214
+ r = run_starlark(
215
+ tiltdir,
216
+ "load('@ORCHESTRATOR/builders/typescript.star', 'prebuild_dockerignore')\n"
217
+ f"r = {{'content': prebuild_dockerignore({str(dockerfile)!r}, {str(project)!r}, "
218
+ "'services/analytics/data-governance-api')}\n",
219
+ )
220
+ lines = r["content"].splitlines()
221
+ res = "services/analytics/data-governance-api"
222
+ assert lines[0] == "*"
223
+ for allowed in ["package.json", "bun.lock", res, "shared-platform-engineering/docker-templates",
224
+ "shared-platform-engineering/platform-logging"]:
225
+ assert "!" + allowed in lines, (allowed, lines)
226
+ # Only the service's own relative path is allowed, never the absolute one.
227
+ assert not any(line.startswith("!" + str(project)) for line in lines), lines
228
+ # Re-excludes come after the allowlist (dockerignore: later lines win).
229
+ assert res + "/node_modules" in lines and res + "/*.md" in lines
230
+ assert lines.index(res + "/node_modules") > lines.index("!" + res)
231
+ # The Dockerfile's own negations aren't carried over (same as docker_build's ignore=).
232
+ assert not any(".env.example" in line for line in lines)
233
+
234
+
194
235
  def test_resolve_manifest_dependency_names_dedupes_and_skips_empty(tmp_path):
195
236
  manifest = {"dependsOn": []}
196
237
  assert _run_resolve_names(tmp_path, manifest, {}) == []
@@ -1,62 +0,0 @@
1
- # TDK Codebase Audit Report
2
-
3
- Generated: 2026-04-29
4
-
5
- ## Summary
6
-
7
- - **Total markers found:** 4
8
- - **CLI (User-facing):** 4
9
- - **Discovery:** 0
10
- - **Engine:** 0
11
-
12
- ## Findings
13
-
14
- ### CLI (User-Facing) - Priority: HIGH
15
-
16
- ```
17
- cli/src/commands/resource.ts:164: // TODO: Check database, cache, etc.
18
- cli/src/commands/resource.ts:168:// TODO: Add your routes here
19
- cli/src/commands/resource.ts:231:// TODO: Implement your worker logic here
20
- cli/src/commands/config.ts:32: // TODO: Implement diff logic
21
- ```
22
-
23
- **Details:**
24
-
25
- 1. **resource.ts:164** - Database/cache health check TODO in backend index template
26
- - Context: Health check endpoint needs to verify database/cache connectivity
27
- - Impact: Generated services won't properly report health status
28
-
29
- 2. **resource.ts:168** - Routes placeholder TODO in backend index template
30
- - Context: Placeholder comment for developers to add their own routes
31
- - Impact: Documentation/placeholder - low functional impact
32
-
33
- 3. **resource.ts:231** - Worker logic TODO in worker index template
34
- - Context: Worker template only has a basic loop, no actual job processing
35
- - Impact: Generated workers aren't functional without implementation
36
-
37
- 4. **config.ts:32** - Diff logic TODO in config regenerate command
38
- - Context: Dry-run mode shows what would change but doesn't implement actual diff
39
- - Impact: Users can't see differences between current and new config
40
-
41
- ### Discovery - Priority: MEDIUM
42
-
43
- ```
44
- No findings
45
- ```
46
-
47
- ### Engine - Priority: MEDIUM
48
-
49
- ```
50
- No findings
51
- ```
52
-
53
- ## Next Steps
54
-
55
- 1. ✅ Review HIGH priority (CLI) findings - COMPLETED
56
- 2. Implement or remove TODOs as appropriate:
57
- - Implement health check with database/cache verification (resource.ts:164)
58
- - Add example routes template (resource.ts:168)
59
- - Create functional worker template with job processing structure (resource.ts:231)
60
- - Implement diff logic for config dry-run (config.ts:32)
61
- 3. Add tests for any new functionality
62
- 4. Re-run audit to verify cleanup
@@ -1,5 +0,0 @@
1
- schema: spec-driven
2
- created: 2026-05-04
3
- status: completed
4
- completed: 2026-05-04
5
- commit: cfa2ffc
@@ -1,94 +0,0 @@
1
- ## Context
2
-
3
- TDK CLI is a multi-language monorepo (TypeScript CLI, Python Discovery, Starlark Engine) that has grown organically. Previous cleanup efforts have addressed specific issues, but a comprehensive, systematic cleanup across all dimensions is needed.
4
-
5
- **Current State:**
6
- - Code duplication exists across CLI commands and utilities
7
- - Type definitions are scattered and sometimes duplicated
8
- - Unused imports and functions remain from refactors
9
- - Circular dependencies exist in the module graph
10
- - Weak types (`any`, `unknown`) are used extensively
11
- - Defensive try/catch patterns hide errors unnecessarily
12
- - Legacy fallback code remains from migrations
13
- - AI-generated comments and stubs litter the codebase
14
-
15
- **Previous Cleanup Work:**
16
- - Dead code elimination assessment completed (2026-04-30)
17
- - Circular dependency critical assessment completed (2026-05-01)
18
- - Type assessment report available (2026-05-03)
19
- - AI slop assessment completed (2026-05-03)
20
- - Deduplication assessment completed
21
-
22
- ## Goals / Non-Goals
23
-
24
- **Goals:**
25
- - Achieve 100% DRY compliance for code patterns appearing 3+ times
26
- - Consolidate all shared types into centralized type modules
27
- - Remove 100% of verified unused code (knip + manual verification)
28
- - Resolve all circular dependencies in the module graph
29
- - Replace 95%+ of weak types with strong, researched types
30
- - Remove all unnecessary defensive programming patterns
31
- - Eliminate all deprecated, legacy, and fallback code
32
- - Remove all AI slop, stubs, and unhelpful comments
33
-
34
- **Non-Goals:**
35
- - Complete rewrites of working functionality
36
- - Breaking changes to public APIs
37
- - Adding new features during cleanup
38
- - Perfection at the cost of progress (80/20 rule applies)
39
-
40
- ## Decisions
41
-
42
- **Decision 1: Research-First Approach for Types**
43
- - **Rationale**: Weak types must be replaced with correct types, not guesses
44
- - **Implementation**: Research actual runtime values, package types, and usage patterns before replacing `any`/`unknown`
45
-
46
- **Decision 2: Verification Before Removal**
47
- - **Rationale**: Dead code removal must not break working systems
48
- - **Implementation**: Use knip for detection, then verify with manual analysis and tests before removal
49
-
50
- **Decision 3: Parallel Subagent Execution**
51
- - **Rationale**: 8 independent workstreams can proceed simultaneously
52
- - **Implementation**: Each dimension has a dedicated subagent with clear scope
53
-
54
- **Decision 4: Critical Assessment Required**
55
- - **Rationale**: Each subagent must deeply understand current state before changing
56
- - **Implementation**: Every subagent produces a critical assessment document before implementing
57
-
58
- **Decision 5: High Confidence Only**
59
- - **Rationale**: Low-confidence changes risk introducing bugs
60
- - **Implementation**: Only implement recommendations with clear evidence and low risk
61
-
62
- ## Risks / Trade-offs
63
-
64
- **Risk: Removing code that appears unused but is dynamically loaded**
65
- - **Mitigation**: Manual verification beyond static analysis; test execution verification
66
-
67
- **Risk: Type replacements break runtime behavior**
68
- - **Mitigation**: Research actual values; use runtime checks if needed
69
-
70
- **Risk: Circular dependency fixes require architectural changes**
71
- - **Mitigation**: Document current state; propose minimal fixes; avoid major refactors
72
-
73
- **Risk: Defensive programming removal exposes hidden bugs**
74
- - **Mitigation**: Replace error-hiding with explicit error handling only where needed
75
-
76
- **Risk: Scope creep across 8 dimensions**
77
- - **Mitigation**: Strict boundaries per subagent; time-box each dimension
78
-
79
- ## Migration Plan
80
-
81
- No user-facing migration needed. Internal changes only.
82
-
83
- Deployment steps:
84
- 1. Execute all 8 subagents in parallel for research phase
85
- 2. Review all critical assessments
86
- 3. Implement high-confidence changes per dimension
87
- 4. Run full test suite after each dimension completes
88
- 5. Merge incrementally by dimension to limit blast radius
89
-
90
- ## Open Questions
91
-
92
- 1. Should we establish permanent tooling (knip, madge) in CI?
93
- 2. What's the policy for `any` types that are truly unavoidable?
94
- 3. Should we create a style guide to prevent future AI slop?