Skip to content

refactor(phase-3): shared runner-core — meshapi consolidation + config/report/meshapitest - #56

Closed
grubmeshi wants to merge 1 commit into
refactor/single-go-binary/phase-2b-bugfixfrom
refactor/single-go-binary/phase-3-shared-core
Closed

refactor(phase-3): shared runner-core — meshapi consolidation + config/report/meshapitest#56
grubmeshi wants to merge 1 commit into
refactor/single-go-binary/phase-2b-bugfixfrom
refactor/single-go-binary/phase-3-shared-core

Conversation

@grubmeshi

Copy link
Copy Markdown
Collaborator

Phase 3 — Shared Runner-Core & Client Consolidation (partial)

Consolidates five disjoint sub-agent slices into one always-green branch. This landing covers the shared-package foundations (plan steps 2–5 + the three new standalone packages); the consumer-rebase / de-global steps (6,7,8,9,10,11) were not produced by any slice and are deferred — see "Not delivered" below. Opening as draft accordingly.

Delivered (green)

meshapi client consolidation (steps 2–5)

  • HttpError{StatusCode, ResponseBody} + IsNotFound/IsConflict/IsForbidden + AsHttpError, replacing status-only StatusError (provider-shaped, D3/§7).
  • Identity{Name,Version} + UserAgent(); deletes runnerName/runnerVersion/SetClientMetadata (last deferred mutable global in the module).
  • Retry transport (retryTransport, RetryOptions, ExponentialBackoff) per §5.2.3.
  • Pluggable Logger seam copied verbatim from the provider (§5.2.6).
  • Client split RunClient/RunnerClient; registration PUT + v1-preview media type moved out of controller/registration.go, wire byte-identical.
  • Consumers migrated behavior-identical (controller, tf, both mains).

New shared packages (born standalone, gated ≥90)

  • config (§5.3, D7): two-file deep-merge loader, ${VAR} interpolation, legacy-env fail-fast, shared Api section (user/username alias), Env bindings, LogLevel.
  • report (§5.4, D4): ExecutionStatus/RunStatus/StepStatus/Output, Progress, RunLog, Observer, Reporter, ToStatusUpdate.
  • meshapitest (§5.7): httptest meshfed-API mock server; ungated test-only helper.

Gates

  • task test green (all 3 modules); tf -race green.
  • task lint green (0 issues, 3 modules).
  • Coverage: config 95.9%, meshapi 90.6%, report 99.2% (all new gate lines pass); tf holds 90.4%.

Sanctioned deltas

  • Retry/backoff on meshapi (429/502/503/504/transport-error, idempotent + whitelisted POST) — the D3 phase-3 mandate; inert on happy paths; STOP-D transcript-neutral (§5.2.3, §8).
  • Additive LOG_LEVEL env + meshapi DEBUG wire-body logging seam (inert at default info); main handler-level wiring lands phase 4 (§5.2.6).
  • tf reporting reduced from full-snapshot to changed-steps-only diff sends — backend-result-identical (upsert + cumulative-replace); tf transcript pins updated for the diff shape (§5.4).
  • Interface deviations vs the plan's illustrative signatures: RunnerClient.Update(uuid, jsonBody []byte) (keeps controller-side marshal-vs-PUT metric split, D12), stateful config.Loader (per-startup consumed-env tracking, P3), Observer.Run extra done chan, NewRunLog (*RunLog, error), ExecutionStatus.String() returns "UNKNOWN" (no panic).

NOT delivered by any slice (deferred; exit criteria NOT fully met)

  • Step 7 — controller de-global: AppConfig, DiscoveredOidcIssuer, UseTestClient and the metricsInstance/metricsOnce singleton all remain. The injectable NewMetricsCollector(reg prometheus.Registerer) seam (§5.6) that phase 4 assumes is NOT in place — flagged as a cross-plan issue.
  • Steps 6 / 9 — consumer rebases: config and report are unused by tf/controller (they keep their own config + reporting types; duplication remains until the rebase).
  • Step 8 — decryption move: controller/decryption.go not moved into meshapi; crypto has no Decrypt method and stays at 71.4% (no crypto gate line added — it would fail).
  • Step 10 — lint debt: the .golangci.yml controller/go-meshapi-client errcheck/forcetypeassert/makezero exclusion blocks are still present (13 findings would surface if removed, incl. untouched crypto).
  • Step 11 — acceptance run: not performed.

See PLAN_DETAIL_03_shared_core.md §6 for the full step list and the structured run report for the uncertainty list.

🤖 Generated with Claude Code

…g/report/meshapitest packages

Phase 3 (PLAN_DETAIL_03_shared_core.md) partial landing — the shared-core
package foundations, consolidated from five disjoint sub-agent slices.

meshapi (steps 2–5):
- HttpError{StatusCode, ResponseBody} + IsNotFound/IsConflict/IsForbidden +
  AsHttpError, replacing the status-only StatusError (provider-shaped, D3/§7).
- Identity{Name,Version} + UserAgent(); deletes the runnerName/runnerVersion/
  SetClientMetadata package globals (last deferred mutable global in the module).
- retryTransport + RetryOptions/ExponentialBackoff: GET/PUT/DELETE always retry,
  POST only whitelisted (/status/source, /api/login); claim POST + status PATCH
  never retried; 429/502/503/504/transport-error retryable, 500 not; Retry-After
  honored (cap 5min); MaxRetries 4, 1–8s (§5.2.3).
- Pluggable Logger seam copied verbatim from the provider (noop default, SlogLogger
  adapter, Authorization [REDACTED] as the one sanctioned mask; artifact stream never
  body-logged) (§5.2.6).
- Client split: RunClient (run endpoints, Client=RunClient alias) + RunnerClient
  (registration PUT moved out of controller/registration.go, wire byte-identical).
- Consumers migrated (behavior byte-identical): controller.go/runapi.go/registration.go,
  tf worker.go/runapi.go, both mains (SetClientMetadata dropped).

New shared packages (born standalone, gated ≥90):
- config (§5.3, D7): two-file deep-merge loader, ${VAR} interpolation, D7 legacy-env
  fail-fast, shared Api section (user/username alias), Env bindings, LogLevel helper.
- report (§5.4, D4): ExecutionStatus/RunStatus/StepStatus/Output, Progress, RunLog,
  Observer (10s ticker, abort-cancel, async SUCCEEDED→IN_PROGRESS), Reporter, ToStatusUpdate.
- meshapitest (§5.7): httptest-backed meshfed-API mock server (claim/register/PATCH/
  artifact) with seedable runs + captured requests; ungated test-only helper.

Gate: thresholds.txt gains config 90 / meshapi 90 / report 90 (all pass:
config 95.9%, meshapi 90.6%, report 99.2%); tf gate holds at 90.4%.

Deferred to a follow-up (not delivered by any slice; see PR body): controller
de-global (AppConfig/DiscoveredOidcIssuer/UseTestClient, metrics singleton — step 7),
config/report consumer rebases (steps 6/9), decryption move + crypto gate (step 8),
lint-debt exclusion-block removal (step 10), acceptance run (step 11).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@grubmeshi

Copy link
Copy Markdown
Collaborator Author

Superseded by #65, which consolidates the plan + all phases 0→7 + the phase-3/5 remediation into a single reviewable PR (with all plan/run artifacts and a code-verified FOLLOW_UP.md). Closing in favor of #65.

@grubmeshi grubmeshi closed this Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant