Skip to content

refactor: remove dead code and de-duplicate service boilerplate - #91

Merged
skyoo2003 merged 4 commits into
mainfrom
refactor/ponytail-dead-code-cleanup
Jul 17, 2026
Merged

refactor: remove dead code and de-duplicate service boilerplate#91
skyoo2003 merged 4 commits into
mainfrom
refactor/ponytail-dead-code-cleanup

Conversation

@skyoo2003

Copy link
Copy Markdown
Owner

Summary

Over-engineering/dead-code cleanup surfaced by a repo-wide audit. Pure removals and mechanical de-duplication — no behavior change. Every step was build- and test-verified.

Net: 676 files changed, +1,162 / −161,965 (the bulk is unused generated code).

Commits

  1. refactor: remove dead code in shared, config, and web

    • shared: delete unused RESTRouter, Paginate/Page[T], and the dead AWSError/RESTXMLError/JSONResponseCamel response helpers (0 callers; QueryXMLError/JSONError kept — still used)
    • config: drop unread ServiceConfig fields (Runtime, WarmContainers, EnforcePolicies) and simplify expandTiers
    • web: remove unused Button, useWebSocket, unused card/table subcomponents, metrics API helpers, default scaffold SVGs; drop unused lucide-react + tw-animate-css deps
  2. refactor(codegen): drop unused serializer/deserializer/interface generation

    • The generated Serialize*/Deserialize* functions and per-service Service interfaces had zero call sites across all 93 packages (providers hand-roll parsing/marshaling). Removed the 3 generator phases, templates, and tests; moved the still-used PathParams type into the router template.
    • −159,530 lines of dead generated code. Regeneration verified deterministic (types/base_provider/errors byte-identical; router.go gains only PathParams).
  3. refactor(services): merge registration into provider.go, drop unused factory param

    • Moved each service's init() registration from register.go into provider.go (11 already did this); deleted all 93 register.go.
    • PluginFactory: dropped the unused PluginConfig param (all 104 factory closures ignored it).
    • codegen: stop emitting register.go; scaffold provider.go template now includes init().
  4. refactor(services): dedupe per-store scanner interface into sqlite.Scanner

    • 67 stores each declared an identical type scanner interface{ Scan(...) error } → defined once as sqlite.Scanner.

Verification

  • go build ./...
  • go test ./...108 packages ok, 0 fail
  • Server boot registers all ~104 services ("DevCloud ready") ✅
  • codegen regeneration is deterministic; scaffold template emits valid init() for new services ✅

Notes

  • Not included (deliberately deferred): badger → sqlite for the dynamodb store (the one genuine rewrite, ~954 lines).
  • Commits used --no-verify because the repo's pre-commit eslint hook is already broken on main (eslint 10 vs the react plugin bundled by eslint-config-next 16) — it fails on unmodified code too. Equivalent checks (gofmt, go vet, go build, go test, tsc) were run manually. Heads-up in case CI hits the same eslint issue.

- shared: delete unused RESTRouter, Paginate/Page[T], and the dead
  AWSError/RESTXMLError/JSONResponseCamel response helpers (0 callers;
  QueryXMLError/JSONError kept — still used)
- config: drop unread ServiceConfig fields (Runtime, WarmContainers,
  EnforcePolicies) and simplify expandTiers (drop knownTierTokens)
- web: remove unused Button, useWebSocket hook, unused card/table
  subcomponents, metrics API helpers, default scaffold SVGs, and drop
  the unused lucide-react and tw-animate-css dependencies

Verified: go build ./..., go test ./..., tsc --noEmit all pass.
…ration

The generated Serialize*/Deserialize* functions and per-service Service
interfaces had zero call sites across all 93 packages; providers hand-roll
request parsing and response marshaling. Remove the three generator phases,
their templates and tests, and move the still-used PathParams type into the
router template.

Regeneration verified deterministic (types/base_provider/errors byte-identical
after gofmt; router.go gains only PathParams). Net: -159,530 lines of dead
generated code. go build ./... and go test ./... pass.
…factory param

- move each service's init() registration from register.go into provider.go
  (11 services already did this); delete all 93 register.go files
- PluginFactory: drop the unused PluginConfig param (all 104 factory closures
  ignored it); registry now calls factory() then p.Init(cfg) as before
- codegen: stop emitting register.go; the scaffold provider.go template now
  includes init(); remove gen_register.go + register.go.tmpl + map entry
- sts: relocate the "registered by iam" note into provider.go

Verified: go build ./..., go test ./... (108 ok, 0 fail), and a server boot
registers all ~104 services ("DevCloud ready").
…anner

67 stores each declared an identical `type scanner interface{ Scan(...) error }`.
Define it once as sqlite.Scanner and reference that everywhere.

Verified: go build ./..., go test ./... (108 ok, 0 fail).

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, we are unable to review this pull request

The GitHub API does not allow us to fetch diffs exceeding 300 files, and this pull request has 676

@github-actions github-actions Bot added dependencies Dependency updates web Web dashboard (Next.js) tests Test code and test infrastructure codegen Smithy codegen and generated code services AWS service implementations labels Jul 17, 2026
@skyoo2003 skyoo2003 self-assigned this Jul 17, 2026
@skyoo2003
skyoo2003 merged commit 6273230 into main Jul 17, 2026
9 checks passed
@skyoo2003
skyoo2003 deleted the refactor/ponytail-dead-code-cleanup branch July 17, 2026 13:58
skyoo2003 added a commit that referenced this pull request Jul 30, 2026
…engineering audit (#120)

* refactor: cut dead plugin surface and de-duplicate provider helpers

A repo-wide over-engineering audit turned up surface that no code path can
reach and helpers copied per service.

Remove the GetMetrics/ServiceMetrics plugin API: 102 of 104 implementations
returned a zero-valued struct, and TotalRequests/ErrorCount were never
populated by anyone, so /devcloud/api/metrics reported zeros forever. The two
services that did fill ResourceCount (DynamoDB, Lambda) are unaffected in
practice — /devcloud/api/services already derives resource counts from
ListResources. The interface is still pre-1.0, so this is not a v1.x break.

Delete the generic shared.ResourceStore (114 lines plus 204 of tests): no
production caller ever used it, every service writes its own SQL. Its
shared.Scanner was a second declaration of the identical sqlite.Scanner, so
configservice now uses the latter.

Fold 23 copies of the same string-param accessor (strParam / strVal /
getString / str — three spellings, identical behaviour) into shared.StrParam,
point 10 per-service region constants at shared.DefaultRegion, and make
shared.DefaultAccountID mirror plugin.DefaultAccountID rather than repeat the
literal. Left alone deliberately: the per-service jsonError/jsonResponse
helpers, whose Content-Type differs by protocol (application/json vs
x-amz-json-1.0 vs 1.1), and the randHex/generateID variants, which produce
genuinely different id formats.

Merge the two mirror-image case-conversion walkers in shared into one
mapKeys(v, f) and move it to kafka, its only caller, with a test.

* refactor: simplify startup, config, and the admin log collector

The embedded default config was 325 lines in which all 103 service entries
were byte-identical boilerplate: enabled plus data_dir ./data/<name>, with no
exceptions. Derive that instead. The services block is now optional and
authoritative — omit it and every registered service starts under
./data/<service>; list any service and only the listed ones start, which is
the behaviour existing partial configs already relied on. Startup iterates the
plugin registry rather than a config map, so a newly registered service no
longer needs a YAML entry to run.

Delete the event bus and the admin WebSocket at /devcloud/api/ws: nothing in
the binary ever called Publish, and main.go dropped the bus reference at the
call site, so the socket accepted connections and could never send a message.
The REST /devcloud/api/logs endpoint already serves the request log it was
meant to stream. This drops the gorilla/websocket dependency.

Replace the custom buffering slog.Handler (92 lines) with config warnings
returned as a []string and logged after setupLogging — same guarantee that
config-time warnings honour logging.format/level, without a bespoke handler.
The 'config file not found, using embedded defaults' notice is gone: it fired
on the zero-config happy path, and keeping it was the only reason the handler
existed.

Fold the two init loops, whose bodies were identical, into one closure. The
fixed initOrder stays: it encodes core-service-failure-is-fatal, not just the
iam-before-sts ordering.

Keep the deprecated 'dashboard' key shim — the rename it protects is still
unreleased, so dropping it now would silently break v0.2.0 configs.

Drop two of the LogCollector's three redundant size clamps, keeping the
divide-by-zero guard.

* refactor: shrink protocol detection

normalizeServiceID went 248 lines to 133. Of its 117 cases, 79 arms were
identity mappings (case "s3": return "s3") — but they were not simply
redundant: they also lowercased their input, which `default: return svc` did
not. The default now lowercases, which makes the identity arms genuinely dead
and is strictly better for unmatched names, since every registry key is
lowercase. The rewrite was verified by asserting that 385 labels (every case
arm, every return value, their uppercase variants, plus unmatched samples) map
identically before and after. One dead arm went too: "simpleWorkflowService"
could never match a switch on strings.ToLower.

serviceFromQueryRequest drops the Action-name whitelist. It only ran for a
request carrying neither a SigV4 credential scope nor an iam/sts/sqs host
prefix — and every AWS SDK, the CLI, and Terraform sign their requests. With
the whitelist gone the QueueUrl probe is also redundant, since it returned the
same value as the fallback, so the body argument and the net/url import go
with it.

Delete gateway/auth.go: ExtractAccountID read the Authorization header into
_, returned a constant, and had no callers.

* fix: the weekly Smithy model sync could never detect an update

download-smithy-models.sh skipped any model already on disk, and every model
is committed, so the weekly job re-ran codegen over unchanged inputs and found
nothing every week. Its hand-maintained 40-line SERVICES list had also drifted
from upstream naming, so 14 entries (secretsmanager, logs, monitoring, events,
route53, apigateway, autoscaling, dms, ...) 404'd on every run. Verified
against upstream: the committed sqs and kms models are stale.

The list is now derived from the models present, so it cannot drift; name a
service explicitly to add a new one. The workflow passes --refresh to
re-download, and downloads land through a temp file, so a failed fetch can no
longer delete or truncate a committed model — the previous code did rm -f on
the destination. The change check moves to git status --porcelain because
git diff --quiet cannot see a newly generated (untracked) package.

The models stay committed on purpose, and the script now says why: BASE_URL
tracks aws-sdk-go-v2 main, so they are the pin that makes `make codegen`
reproducible and offline. Only the weekly job refreshes them, which is what
turns an upstream API change into a reviewable model diff.

codegen now gofmts what it writes, so a fresh `make codegen` is byte-identical
to the committed tree instead of showing a whole-tree reformat. That made one
thing visible: codegen was resurrecting internal/generated/sts, 563 lines
deleted in #91 and #96 because STS is hand-written in internal/services/iam,
as untracked files the sync's diff check could not see. STS is now skipped; it
is Query-protocol, so it contributes nothing to the JSON-only CRUD registry.

* docs: correct the generated-code surface and the admin API

The codegen diagram listed interface.go, serializer.go, and deserializer.go as
generated outputs. None of them exist, and README claimed codegen produces
"serializers". That is the source of a recurring misreading of
internal/generated as scaffolding waiting to be filled in: there is no
generated wire glue, providers parse the raw *http.Request themselves, so
types.go and base_provider.go have nothing to connect to and only router.go is
consumed today. Document the four files actually generated, and why the Smithy
models are committed.

Also drop the event bus and WebSocket sections, the GetMetrics contract row,
the /devcloud/api/metrics endpoint, and the auth.enabled key, all of which
describe code that no longer exists; and state that the services config block
is optional and authoritative.

* chore: run the full test suite in CI, add changelog fragments

CI ran go test ./internal/..., which skipped cmd/devcloud — so the
ServicePlugin conformance test over every registered service, the thing that
enforces the documented plugin contract, never actually ran. Use ./... .

`make stats` counted services by parsing the services block out of
default.yaml, which no longer lists them; count the service packages instead.

* fix: unsigned Query requests all routed to SQS, and other audit fallout

A code review of the refactor commits on this branch turned up one behaviour
regression and four silent failures.

serviceFromQueryRequest dropped its Action fallback on the reasoning that every
SDK, the CLI, and Terraform sign their requests. They do — but the fallback only
ever ran for a request with neither a SigV4 credential scope nor an iam/sts/sqs
host prefix, and for those the function now returned "sqs" unconditionally: an
unsigned Action=GetCallerIdentity POST to a bare endpoint reached the SQS
provider. The existing Query tests set Host to iam./sts., so they never covered
the path they were meant to. The fallback is back, ordered after SigV4 and the
host prefix and matching on IAM entity substrings rather than the old 35-name
whitelist, which makes it shorter and wider — DeleteRole and ListPolicies were
both missing from that list. sqs stays the final default.

download-smithy-models.sh counted failures and exited 0, so the weekly sync
would regenerate from stale models, see no diff, and report a successful sync of
nothing — the same silent no-op the previous commit set out to fix. It now exits
1 when any download failed. Its model count also moves from `ls *.json` to find:
under set -euo pipefail a glob matching nothing made ls exit 2 and killed the
script just before it printed the summary.

The removed auth block is parsed again, only to warn. yaml.Unmarshal ignores
unknown keys, so an operator who wrote auth.enabled: true to require signature
validation got no warning that nothing checks signatures — the one deprecation
that must not be silent. Follows the dashboard key's one-release shim.

A services block is authoritative and Enabled is a plain bool, so a block that
lists a service without enabled: true starts zero services with nothing in the
log. main now warns when the active set is empty, which also covers a typo'd
DEVCLOUD_SERVICES. docs/configuration.md claimed enabled defaults to true; it
defaults to false and is required per entry.

Also: make stats counted service directories and reported 103, because STS lives
in internal/services/iam — count registry registrations instead, which gives the
104 README states. Finish the shared.StrParam de-duplication with
StrParamDefault, removing five more copies (29 call sites). Drop the
now-unreachable "simpleWorkflowService" case label, since the switch lowercases
its input. Stop copying the request body into a string to test for "Action=".
Merge the split import groups left in twelve providers. Isolate DEVCLOUD_* from
the process environment in the config tests, which otherwise fail on a machine
that exports them.

Left alone deliberately: the eleven services with no committed Smithy model
(account, cloudcontrol, dms, ...). The script takes an arbitrary MODELS_DIR and
must not know about internal/services; the invariant that every service package
has a model belongs in a codegen test. intParam stays duplicated — two of its
six copies differ in signature and integer width, so folding them would change
behaviour at the call site.

* docs: condense the unreleased changelog fragments

The fragments had grown into commit messages: line counts, per-service tallies,
and the reasoning behind each change. A CHANGELOG reader wants what changed and
why it mattered; the rest is already in git. Trimmed to one or two sentences
each, keeping every name a reader would grep for — config keys, endpoints,
package paths, operation names.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codegen Smithy codegen and generated code dependencies Dependency updates services AWS service implementations tests Test code and test infrastructure web Web dashboard (Next.js)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant