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>
krls2020 added a commit that referenced this pull request Jun 15, 2026
docs/spec-authoring-boundary.md is the living truth: what lives inside
the domain (+ the OSS-port flow's documented future home and handler
rules), the L1-L4 laws with their depguard/test pins, the C1-C6 runtime
contract list, gate semantics, ownership-by-path, and operational notes
(Aleš's env, flow-eval env propagation). CLAUDE.md gains the boundary
invariant bullet + updated dependency table; the architecture spec's
per-package row and the content-surface/rubric spec paths follow the
move. v2-remnant retirement is backlogged with inventory + promote
trigger (plans/backlog/v2-recipe-remnants.md); both plan docs archive
with a deviations ledger (P4 moot — PR #5 will not merge; atom-vars
check stays in authoring/analyze because its subject is authoring
content).

Plan: plans/archive/authoring-boundary-2026-06-11.md (P5)
krls2020 added a commit that referenced this pull request Jun 15, 2026
… override + measured-mode emission

Recipe-side hunks of the PR #5 (feat/oss-port-flow) integration, applied
onto the moved internal/authoring/recipe path:

- Plan.GlueRepoURL: per-plan buildFromGit override for the OSS port flow's
  single self-referential glue repo — BOTH emit sites (runtime + the
  ServiceKindUtility branch), canonicalized via topology.CanonicalRepoURL.
  Framework path (empty) stays byte-identical.
- Service.ModeMeasured + ManagedServiceModeForTier: single mode-resolution
  owner for the two emit sites; a port-MEASURED service emits its measured
  mode verbatim (no family-table force-promotion at tier 5), framework
  services keep the run-12 §Y3 family-table behavior.
- clickhouse joins the HA-capable family table (proven by
  fxck/recipe-posthog — mandatory for PostHog's ON CLUSTER DDL).
- SubstituteFragmentMarkers exported for the port capture stage (pure
  re-export); doc comments unglued from the unexported worker.

Pinned by TestEmitDeliverableYAML_GlueRepoOverride,
TestManagedServiceModeForTier, TestManagedServiceSupportsHA_FamilyTable.
krls2020 added a commit that referenced this pull request Jun 15, 2026
…ntegration)

Full integration of PR #5 (feat/oss-port-flow, never merged), reshaped to
the authoring boundary's prescribed Future-home shape: the whole flow lives
in internal/authoring/port/ as a self-registering ZCP_AUTHORING-gated MCP
tool (recipe.Register model) — NOT a workflow= value, NO WorkflowInput
fields, NO core envelope phase. Semantics preserved 1:1 from the PR.

Engine (recon / fixclass / rubric / fitceiling / harden / progress /
escalate + tests) transplanted verbatim — it was already boundary-clean
(schema + topology only). Two redesigns where the PR coupled to core:

- PortSession is STANDALONE (the PR wrapped workflow.WorkSession): own
  ProjectID/Environment/Intent/ClosedAt/CloseReason fields, own attempt
  recording, terminal iteration-cap close (CloseReason-guarded). Identity
  and time split into two fields — StartTime is an opaque process-instance
  token (recycled-PID guard, now actually CHECKED on load; the PR stored
  it but never verified), CreatedAt is the RFC3339 wall-budget anchor.
  The PR anchored the wall budget on the process-identity field, which is
  unparseable proc-ticks on Linux — the terminator could never fire there.
- Status recovery is the tool's own envelope (kind/tool/phase/nextCall →
  zerops_port action=iterate), not a core Phase.

Tool layer rewritten from internal/tools/workflow_port*.go into the port
package: PortInput (de-prefixed fields: target, failureClass, signals,
deploySucceeded, importOverride, rubric, glueRepo, unresolved,
publishDryRun), own FlexBool + error wire (code/error/suggestion/recovery
vocabulary, recovery → zerops_port status), schema derivation with
FlexBool oneOf patching across the nested input tree. Capture rewired:
recipe emit verbs → authoring/recipe, curated publish →
authoring/publish.{CreateRecipeRepo,PushAppSource,Recipe} over the
core-sync config surface (C5).

Boundary mechanics in the same commit (the deliberate-contract-change
rule): depguard authoring-allowlist admits jsonschema-go (the mcp go-sdk's
own schema vocabulary — mcp.Tool.InputSchema IS *jsonschema.Schema) +
spec L2 row updated; C3 state-namespace contract now PINNED by
TestAuthoringBoundary_StateNamespaces (AST scan of every
filepath.Join(stateDir, …) site — authoring owns port/ + port-recipes/,
core owns the rest) with scanner self-test; TestNoCrossCallHandlerState
roots include authoring/port; server registers port.Register inside the
gate; TestServer_AuthoringToolsRegistered + TestAnnotations_AuthoringTools*
cover zerops_port.
krls2020 added a commit that referenced this pull request Jun 15, 2026
…<OSS> recipe' reaches zerops_port

- docs/spec-oss-port-flow.md: the runtime/architecture reference adopted
  from PR #5 and rewritten for the shipped shape (gated zerops_port tool in
  internal/authoring/port/, standalone session, tool-owned status recovery;
  no workflow=port, no PhasePortActive). Status: shipped 2026-06-12;
  remaining live e2e verification + OQ-1 noted.
- agents_authoring.md (gated AGENTS.md block): trigger routing the PR never
  had — 'create umami recipe' / 'port strapi' on third-party OSS routes to
  zerops_port; zerops_recipe stays the framework-showcase tool. Without
  this, zerops_recipe swallowed foreign-OSS prompts and authored them from
  scratch (observed on the eval container). Pinned by
  TestBuildAgentsMD_AuthoringGate + TestAgentsShared_NoAuthoringLeak.
- CLAUDE.md key-specs line + authoring-domain mentions updated (port flow
  shipped, no longer 'future').
- plans/archive/: the three PR #5 design docs archived verbatim (banner on
  the main plan notes the reshaped landing).
krls2020 added a commit that referenced this pull request Jun 15, 2026
…zcprecipator2 + dead refs

Completes the 'as if v2 never existed' sweep on top of the v2 analyze-harness
retirement:

- internal/authoring/recipe/verify.go — DELETED. 104 lines of HTTP
  verification primitives (DefaultVerifier/ReachableHTTP/HealthEndpoint/...)
  introduced by the recipe Phase-2a engine (2b437d3), never wired into the
  v3 engine, zero callers anywhere (prod or test). Not a PR #5 artifact (the
  port flow delegates C3 'serves HTTP' to core zerops_verify). deadcode -test
  ./... is now ZERO across the whole tree.
- docs/zcprecipator2/ — DELETED (214 files, 4.5M). The v2 design + run corpus;
  no Go code embeds or reads it (build-unaffected), no live spec/CLAUDE.md
  references it. Recoverable from git history.
- docs/zcprecipator3/ — the dead '../zcprecipator2/' markdown links neutralized
  to plain prose (follow-the-chain: no broken links left) and the 'v2
  archaeology lives in ../zcprecipator2/' location statements corrected to
  'removed; in git history'. The v2-comparison NARRATIVE (the legitimate
  'why v3 exists' design rationale) is kept — it is design history, not a
  remnant.
- .golangci.yaml — the analyze tagliatelle exclusion comment rewritten: its v2
  justification (spec-defined B-15_* snake_case keys) is gone; the real
  current reason is the v3 harness parsing external session-log records whose
  source key input.file_path is snake_case (must match byte-for-byte).
- internal/content/repo_drift_test.go — removed the now-dead skip entry for the
  deleted internal/content/workflows/recipe tree.

Live code + config now carry ZERO references to any deleted v2 path.
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