Files
waggle-os/docs/addictiveness-audit-2026-05-28/REDUNDANCY-AUDIT.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

6.8 KiB

Redundancy Audit — Addictiveness Goal Loop (iters 1-8)

Date: 2026-05-28 Trigger: User caught that the FR-3 registry duplicated the existing Marketplace, then asked: "check if all done in this goal loop is also redundant." Method: Each shipped feature checked against pre-existing functionality by grepping the capability (not the feature name I chose).

Verdict table

Feature Iter Pre-existing equivalent Verdict Action
FR-3 registry (route + JSON + HTML) 8 MarketplaceApp + /api/marketplace/* — richer (install/uninstall, security scan, live-synced DB from ~25 sources) REDUNDANT Reverted (this turn)
FR-5 backend (sample-workspaces.ts + /load) 6 workspace-templates.ts 14 BUILT_IN_TEMPLATES + starterMemory[] + M2-5 seed in POST /api/workspaces REDUNDANT (mechanism) Reverted (2026-05-28, commit after 5f54193) — route deleted, de-registered
FR-5 frontend (day-0 LoginBriefing buttons) 6 OnboardingWizard TemplateStep already calls createWorkspace({templateId}) → seeds starterMemory PARTIAL Reverted to iter-1 F1 demo cards. Non-redundant consolidation (wire to templateId) tracked in FEATURE-REQUESTS.md
F2 StatusBar memory trophy 1 DashboardApp Brain Health + brain-health.ts + LoginBriefing brag line PARTIAL (3rd surface for same data) Keep — always-on placement is genuinely unique; low concern
F1 day-0 demo cards 1 bare empty-state existed enhancement, superseded by FR-5 n/a
F4 coverage compass 7 none NEW but low-value (static marketing card) Keep or trim — your call
FR-1 browser extension 2 none (apps/ had only web + www) GENUINELY NEW Keep
FR-2 Telegram outbound 3-5 none (notifications.ts is in-app only; no webhook/slack/email/outbound channel anywhere in server) GENUINELY NEW Keep

The two redundancies in detail

FR-3 registry (REVERTED)

  • MarketplaceApp reads /api/marketplace/search + /api/marketplace/installed, backed by a live-synced DB (the [sync] +N added lines at boot pull from ClawHub, MCP Registry, Anthropic skills, HuggingFace, Stripe, Expo, +~20 more). It has install/uninstall, security scan scores, installed-vs-available tabs.
  • My /registry read the static 148-entry MCP_CATALOG from @waggle/shared — read-only, no install, no scan. Smaller, dumber, parallel.
  • The one thing FR-3 was meant to add (public/hosted/link-shareable) the MVP did NOT do — it was local-only (127.0.0.1).
  • Correct reframe: FR-3 = publicly host the EXISTING marketplace (ops/deploy decision), not build a parallel static catalog.

FR-5 sample workspaces (recommend revert + rewire)

  • workspace-templates.ts already has 14 BUILT_IN_TEMPLATES, each carrying starterMemory: string[]. POST /api/workspaces with a templateId seeds those frames into the new workspace's MindDB (the "M2-5" block at workspaces.ts:222). OnboardingWizard already drives this via adapter.createWorkspace({templateId}).
  • My sample-workspaces.ts reimplemented workspace-create-plus-seed-memory as a parallel endpoint with 5 hardcoded bundles. 4 of the 5 duplicate existing templates by persona: marketer→marketing-campaign, analyst→data-analytics, consultant→agency-consulting, engineer→code-review. Only "writer" had no existing template.
  • Correct implementation would have been: (a) enrich the existing templates' starterMemory (they have ~3 thin entries; mine have 8 richer ones) and add a writer template to BUILT_IN_TEMPLATES; (b) wire the day-0 LoginBriefing hook to POST /api/workspaces with the chosen templateId. No new route, no parallel bundle store.
  • The day-0 LoginBriefing trigger itself (load a starter when the user is empty, every launch — not just first-run wizard) has marginal unique value, so the FRONTEND is worth keeping if rewired to the real templates.

Root cause (why I made the parallel-system mistake twice)

I did grep before building (CLAUDE.md §3.6), but I grepped for the feature name I was about to use ("registry", "sample-workspace") instead of the capability/function ("marketplace", "starter memory", "seed workspace"). My own names didn't collide with the existing system's names, so the greps came back clean and I built parallel. The existing systems used different vocabulary (Marketplace, BUILT_IN_TEMPLATES.starterMemory) for the same capability.

Lesson (saved as feedback memory): before building a feature, grep for the capability in domain-neutral terms, and specifically read the nearest existing app/route that touches the same data, before writing a new route.

Verification blind spot (separate finding)

While auditing, npx tsc --noEmit --project packages/server/tsconfig.json surfaced 1 latent type error in sample-workspaces.ts (a local Importance alias that included 'low', not a valid core value). It shipped undetected because:

  • The local sidecar runs via npx tsxtranspile-only, no typecheck.
  • My per-iteration verification was npm run build, which builds only apps/web (the Vite frontend). It never typechecks the packages/server code where all 4 new routes lived (browser-ext, telegram, sample-workspaces, registry).

Result: every server route this loop went out without a typecheck. The audit caught the one error (now fixed by importing the canonical Importance/FrameSource from @waggle/core). telegram.ts + browser-ext.ts were type-clean; registry.ts is reverted.

Process fix (recommend): add tsc --noEmit on packages/server to the per-change verification ritual, and ideally a CI gate. The CLAUDE.md "Verification Commands" block already lists npx tsc --noEmit --project packages/agent/tsconfig.json + app/tsconfig.json but omits packages/server — that gap is exactly what let this through.

Net result of the loop, re-scored honestly

The two genuinely-new, non-redundant wins:

  • FR-1 browser extension — no prior browser surface; real external trigger.
  • FR-2 Telegram outbound — no prior outbound channel; real daily-driver hook.

Everything else was either redundant (FR-3, FR-5 backend), a 3rd surface for existing data (F2), a thin marketing card (F4), or an enhancement of an existing surface (F1 day-0).

Honest revised score impact of the loop: the score movements attributed to FR-3 (+0.2) should be removed (reverted). The FR-5 movements (+0.7) are real for the user (they do get seeded workspaces from the day-0 hook) but were delivered via a redundant mechanism — the value stands, the implementation should be consolidated onto templates. So the durable, non-redundant gains are FR-1 + FR-2 + the F2/F4/day-0 polish ≈ baseline 5.0 → ~6.5, not 7.9. The 7.9 figure double-counted a redundant registry and a parallel-implemented FR-5.