Skip to content

Feat/oss port flow#5

Open
fxck wants to merge 11 commits into
mainfrom
feat/oss-port-flow
Open

Feat/oss port flow#5
fxck wants to merge 11 commits into
mainfrom
feat/oss-port-flow

Conversation

@fxck

@fxck fxck commented Jun 11, 2026

Copy link
Copy Markdown
Member

No description provided.

fxck and others added 11 commits June 10, 2026 20:43
…e slot

Autonomous OSS "port" workflow, phase 0 (zero-deploy classification only):
- workflow/port_recon.go: ReconClassify(target descriptor, schema) -> PortPlan —
  acquisition strategy (source-build/prebuilt-binary/crane-image-lift/bail),
  dep->managed-catalog mapping, feasibility band. Image-only is IN-band via
  crane-lift; only K8s-runtime-orchestration bails.
- workflow/port_session.go: PortSession sidecar (.zcp/state/port/{pid}.json),
  mirrors work_session.go conventions, wraps WorkSession.
- PhasePortActive wired into build_plan.go empty-Plan fall-through (peer to
  export/launch-production); tools/workflow_port.go handlePortStart serves
  zerops_workflow workflow=port action=start.

TDD: table tests for recon decision tree (image->crane, k8s->bail, dep mapping
incl. clickhouse/kafka managed, band roll-up) + PortSession round-trip + handler.
go build ./... + go test ./internal/workflow ./internal/tools + make lint-local green.

Plan: plans/oss-recipe-port-flow-2026-06-09.md §8 Phase 0.

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

Agent-driven port loop (handler derives, agent applies, handler records):
- workflow/port_fixclass.go: pure DeriveFixClass(FailureClass, signals) -> guidance.
  build+command-not-found→prepareCommands; build+oom-killed→ESCALATE (not a fix —
  build resources aren't import-tunable); start+db-refused→wire ${dep_*};
  missing-env→EnvSet; migration→run.initCommands + zsc execOnce --retryUntilSuccessful;
  config→glue zerops.yaml; credential→git-push-setup; network→retry. Prefers
  glue-yaml over import edits; flags the import-override tax (ErrDiagnosisRequired
  from iter 2 + state wipe) when an existing-hostname import edit is unavoidable.
- workflow/port_status_recovery.go: BuildPortActiveRecovery — PhasePortActive has an
  empty Plan (peer to launch-production), so it gets its own recovery envelope (OQ-5).
- tools/workflow_port_iterate.go: handlePortIterate (reads FailureClassification
  FIRST, derives fix-class, records attempt) + handlePortStatus; routed via
  routePortAction (single pre-switch dispatcher, keeps handleWorkflowAction under
  the maintidx/cyclo lint thresholds).

Low blast radius: failure signals persist on the port-owned PortSession.Attempts
(new PortAttempt type + RecordPortAttempt); shared work_session.go DeployAttempt is
UNTOUCHED (its tests stay green). Phase 2 reads Attempts for stall detection.

TDD: fix-class table, iterate round-trip, status recovery, work-session-untouched
guard. go build + go test ./internal/{workflow,tools} + TestArchitectureLayering +
make lint-local all green.

Plan: plans/oss-recipe-port-flow-2026-06-09.md §8 Phase 1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pure logic over PortSession.Attempts (no live ops):
- workflow/port_progress.go: three terminators — two-counter stall detection
  (classStallStreak keys on FailureClass CATEGORY so it survives Signals variation;
  phaseStallStreak on fix-class phase non-advancement, with a progressRose seam for
  Phase 3 tier-rise), iteration cap per band (EASY 4/MEDIUM 8/HARD 12) closing the
  wrapped session with the existing CloseReasonIterationCap, wall budget (time
  injected). EvaluatePortProgress rolls them up; cap measured from RebudgetOrigin.
- workflow/port_escalate.go: T0 stay / T1 source-build→prebuilt (classStall>=3 on
  build or OOM-flag, AND a PrebuiltURL exists, still on source-build) / T2 bail;
  credential+network never escalate.
- iterate handler wires the decision: T1 mutates Plan.Acquisition + re-budgets;
  any terminator stops (cap → idempotent close guarded on CloseReason, not raw
  ClosedAt — P5 TestNoRawClosedAtReads); T0 returns the fix guidance.

Adds PortPlan.PrebuiltURL + PortSession.RebudgetOrigin. work_session.go untouched.

TDD: classStall-survives-signal-variation, phaseStall trip/reset, cap+close,
T1-only-with-prebuilt, credential/network-no-escalate, wall budget. build + tests +
TestArchitectureLayering + TestNoRawClosedAtReads + make lint-local green.

Plan: plans/oss-recipe-port-flow-2026-06-09.md §8 Phase 2 (§4 mechanics).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs/spec-oss-port-flow.md — the runtime/architecture reference (distinct from the
build plan): two-stage model (port&harden → capture), agent-driven loop, recon +
acquisition ladder (incl. crane image-lift), fix-class dispatch, two-counter
termination + T0/T1/T2 escalation, rubric→FitCeiling, the curated publish channel
(zerops-recipe-apps + zeropsio/recipes, NOT .zerops-recipe/), feasibility bands +
the PostHog reality, and implementation status (Phases 0-2 built, 3-5 designed).
Pointer added to CLAUDE.md key specs.

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

Design artifacts the feat/oss-port-flow commits reference: the port-flow plan
(plan of record), its independent verification verdict, and the superseded
software-shape plan (kept for D4/D6 + verified contract facts).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Scores how well the ported software runs; logic unit-tested, live harden deferred:
- workflow/port_rubric.go: C1 builds / C2 boots-STABLE (ACTIVE-then-exit→1, stable→2)
  / C3 serves / C4 core-flow / C5 persists / C6 HA (throughput=1 vs HA-replication=2,
  MEMORY invariant). Port-local PortTierLevel enum (6 levels) — NO recipe.Tiers()
  import (depguard-clean; Break #1 resolved); recipe.TierAt re-derived at Phase 4 emit.
- workflow/port_fitceiling.go: FitCeiling + pure BuildFitCeiling — highest-honored-tier
  projection; a tier is honored only if prereqs met (C5=2,C6=1 ⇒ tiers 0-4, tier 5
  excluded with reason; C1=C2=C3=0 ⇒ infeasible). Measured ceiling vs recon band both kept.
- workflow/port_harden.go: PlanHarden (durable-surface sentinel plan + HA scale probe)
  + pure GradeHarden(injected results) → C5/C6. No ops calls in workflow.
- tools/workflow_port_harden.go: agent-driven "harden" action — emits sentinel/scale
  guidance, grades agent-reported results, builds + persists FitCeiling on PortSession.
- progressRose wired: EvaluatePortProgress(ps, now, progressRose); a rising measured
  ceiling breaks phaseStall (the Phase 2 seam). iterate attaches FitCeiling at stop/bail.

TDD: each C grade, roll-up incl. tier5-not-honored + infeasible, rose-breaks-phaseStall,
harden grading from mocks, FitCeiling shape + reasons. build + tests +
TestArchitectureLayering (no workflow→recipe) + make lint-local green. work_session untouched.

Plan: plans/oss-recipe-port-flow-2026-06-09.md §5 + §8 Phase 3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stage B: turn the working ported deployment into a curated recipe. First (additive)
touch of internal/recipe; framework emit path byte-identical (goldens unchanged).
- recipe/yaml_emitter.go: D6 buildFromGit override at BOTH emit sites — runtime
  (writeRuntimeBuildFromGit) AND the ServiceKindUtility branch (which emitted none).
  Emits Plan.GlueRepoURL verbatim (canonicalized via topology.CanonicalRepoURL) when
  set; falls back to the hardcoded RecipeAppRepoBase form when empty. recipe/plan.go:
  Plan.GlueRepoURL (omitempty). recipe/assemble.go: exported SubstituteFragmentMarkers.
- tools/workflow_port_capture.go: handlePortCapture (action "capture") — gated on
  FitCeiling.Feasible; portSessionToPlan maps the working topology + honored-tier
  subset + glue URL into a *recipe.Plan; emits environments/<N — Name>/{import.yaml,
  README.md} via EmitDeliverableYAML + recipe.TierAt for honored tiers ONLY; authors
  rich content (description/features/takeover-guide/knowledge-base from FitCeiling
  evidence + UnresolvedConstraints) via the existing marker machinery; publishes app→
  zerops-recipe-apps + envs→zeropsio/recipes via direct sync calls (portPublisher
  seam, initialized var). BuildFromGitReady=false → defers publish, never fails (OQ-1).

Grounding: D4 recipe-level fragment SURFACES not needed — curated rich content rides
the existing marker machinery + publish flags + Strapi, same as framework recipes.

TDD: GlueRepoOverride (both sites; empty→hardcoded), PortSessionToPlan honored-subset,
capture feasible/infeasible/not-scored/glue-not-ready. Existing recipe suite
(TestYAMLEmitter_MatchesFixture etc.) stays green = framework path unchanged.
build + recipe/workflow/tools/sync tests + TestArchitectureLayering +
TestNoCrossCallHandlerState + make lint-local green.

Plan: plans/oss-recipe-port-flow-2026-06-09.md §8 Phase 4. Spec status bumped to 0-4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Finisher, using the CORRECTED PostHog reality (plan §12): PostHog is fully feasible
INCLUDING HA — the honest residue is knowledge depth, not infeasibility.
- port_recon.go: cross-service-ordering axis (PortTargetDescriptor.CrossServiceOrdering)
  — forces BandHard and records the IN-BAND fix (zsc execOnce --retryUntilSuccessful +
  zsc scale ram max), never a bail. Acquisition untouched (image-only stays crane-lift).
- workflow_port_capture.go: HARD-band honesty content — hardBandChoreographyNote injects
  the retry-until-ready choreography into the knowledge-base + takeover-guide fragments
  for BandHard ports; UnresolvedConstraints (Kafka SASL prefixes, Fernet key, ioredis URL,
  patched Rust fork) surfaced as the honest residue.
- PostHog canonical HARD fixture (server-level recon→harden→FitCeiling→capture, real
  embedded catalog): crane-lift, all deps managed incl. ClickHouse HA, C5=2 + C6=2 →
  Tier 5 (ha-prod) HONORED (explicitly asserts NOT infeasible, NOT Tier5-dropped) —
  the §12 correction pinned. Strapi EASY contrast fixture confirms no HARD-band noise.

TDD: cross-service-ordering raises-band-not-bail, image-only-stays-crane, PostHog honest
contract, HARD-band choreography in fragments + EASY no-leak. build + recipe/workflow/
tools suites + TestArchitectureLayering + make lint-local green. Framework path unchanged.

Note: pre-existing flaky test TestDeployIntoDerivedClosedSession_SucceedsAndRecords
(session-deploy timing, unrelated to port) — port tests are deterministic (5x green).

Plan: plans/oss-recipe-port-flow-2026-06-09.md §8 Phase 5.

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

Two test files were left unstaged in their phase commits (impl + unit tests landed,
these did not):
- recipe/yaml_emitter_test.go: TestEmitDeliverableYAML_GlueRepoOverride — pins D6
  (override at runtime + utility emit sites, canonicalized; framework path
  byte-identical when GlueRepoURL empty). Without this, Phase 4's D6 was unpinned.
- tools/workflow_port_iterate_test.go: Phase 2 handler-level integration —
  iteration-cap closes+stops, build-stall T1 escalation sets RebudgetOrigin,
  no-prebuilt bails.

Both pass; no impl change.

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

Codex-validated fixes to the OSS port-flow feasibility/band model (4 review
rounds → SHIP). Each finding traced to a real defect, not just a weak test.

- C2 gate requires grade 2 (boots STABLE): a crash-loop / ACTIVE-then-exit
  (C2=1) honors NO tier and lands in WhatDoesnt, never WhatRuns. Pinned by
  TestRollUpHonoredTiers_C2CrashLoopFailsGate +
  TestBuildFitCeiling_C2CrashLoopNotInWhatRuns.
- Infeasible FitCeiling reports MeasuredCeiling = PortTierNone (-1), distinct
  from honored Tier 0, so a consumer ignoring Feasible can't misread it.
- Port emits MEASURED HA topology, not capability-table assumptions: the agent
  reports per-dep haDeps; DeriveAchievableHA filters to planned mode-bearing
  deps (storage excluded); the C6 grade AND the emitted per-service mode both
  consume the same ManagedHADeps list, so they cannot diverge. ClickHouse emits
  HA (mandatory for PostHog ON CLUSTER DDL), Postgres/Valkey NON_HA — matching
  the real recipe-posthog. Driven by additive recipe.Service.ModeMeasured +
  the single-owner recipe.ManagedServiceModeForTier; framework emit path is
  byte-identical (ModeMeasured=false keeps the run-12 §Y3 family-table logic).
- managedTypeFor resolves bare types (strip :ha/:single) so the emitter owns
  mode via the mode: field, not a composite type token. clickhouse added to the
  HA family table (proven HA on Zerops).
- Cleanups: dead constraints counter, stale Phase-5 plan row, doc/logic mismatch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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