Skip to content

build/devenv: serialize raw phased output map, version-aware load#1140

Merged
winder merged 1 commit into
mainfrom
will/devenv-phased-no-cfg
Jun 2, 2026
Merged

build/devenv: serialize raw phased output map, version-aware load#1140
winder merged 1 commit into
mainfrom
will/devenv-phased-no-cfg

Conversation

@winder
Copy link
Copy Markdown
Collaborator

@winder winder commented May 29, 2026

PR Chain

There are multiple open pull requests that feed into each other:

Description

The phased devenv (--env-mode phased) previously reconstructed a transitional *Cfg from the component runtime's output map via hand-written sync blocks. This PR removes that bridge: NewPhasedEnvironment now serializes the raw accumulated output map directly, and LoadOutput[Cfg] switches on a version marker to decode either format. Adding a new serialized output no longer requires touching a central mapping — a component just publishes a public key.

What changed

  • NewPhasedEnvironment returns the raw accumulated map and writes the output file via storePhasedOutput, which strips runtime-only keys (any key prefixed with _) and serializes the rest. The schema version is re-published as a public key so the file starts with version = N.
  • Component output keys reclassified into public (serialized) vs. _-private (runtime-only, stripped):
    • protocol_contracts: _cldf → cldf, _topology → environment_topology (consumers in executor/committeeccv updated).
    • committeeccv: shared_tls_certs → _shared_tls_certs (consumer in indexer updated).
    • jd stays public (needed for future job proposals); JDInfrastructure.OffchainClient (a live gRPC client) is tagged toml:"-" so the section serializes cleanly while keeping jd_output + node_id_map.
  • LoadOutput[Cfg] is now version-aware — a single dispatch point that all readers (NewLibFromCCVEnv and the ~18 direct LoadOutput[ccv.Cfg] test call sites) funnel through:
    • version absent/0 → existing strict Cfg decode (legacy/monolith).
    • version == 1 → lenient decode of the raw map + derive aggregator/indexer endpoint maps from each launched service's Out.
    • any other version → error.
  • env.toml drops its version key so monolith output stays at 0 and routes to the legacy decoder.

Why

  • Removes the fragile, hand-maintained *Cfg reconstruction in the phased path.
  • Establishes a clear "public key vs. _-private runtime key" convention owned by each component.
  • Keeps the output-file contract backward compatible: no reader signatures or call sites change, because the version dispatch lives inside LoadOutput.

Compatibility / risk

  • Legacy (monolith) output and all its readers are unchanged.
  • Phased output keys are a raw component dump; the phased decode is intentionally lenient and ignores keys Cfg doesn't model (e.g. the aggregators/verifiers plurals).

Testing

Checklist

  • Breaking changes documented in changelog (see changelog directory)
  • Cross link related PRs (in this or other repositories)
  • just lint fix - no new lint errors
  • just generate - mocks and protobufs are up to date

makramkd
makramkd previously approved these changes Jun 2, 2026
Comment thread build/devenv/config.go
Comment on lines +101 to +103
// - version 0 / absent — the legacy monolith output, a strict Cfg dump.
// - version 1 — the phased output, a raw component-output map; the required
// components are decoded out of it and the endpoint maps are derived.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: can these be made constants defined somewhere in the devenv package?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I don't think it's useful to treat a version number like a feature flag. This is more of a backwards compatibility gate. If we end up needing a constant at some point we can add it later.

@winder winder force-pushed the will/devenv-toml branch from 6459776 to e81dc44 Compare June 2, 2026 14:32
Base automatically changed from will/devenv-toml to main June 2, 2026 15:50
@winder winder dismissed makramkd’s stale review June 2, 2026 15:50

The base branch was changed.

NewPhasedEnvironment now serializes the raw accumulated component
hand-built PhasedOutput, and re-emits the schema version as a public
key. LoadOutput[Cfg] switches on that version: absent/0 keeps the
strict legacy Cfg decode, while version 1 leniently decodes the
phased map and derives the aggregator/indexer endpoint maps — so all
existing readers and NewLibFromCCVEnv are unchanged.

Components now own their public output keys: protocol_contracts emits
cldf and environment_topology, while shared TLS certs become a private
"_"-key. jd stays public, with JDInfrastructure.OffchainClient marked
toml:"-" so the live client is skipped but the JD output and node IDs
persist for future job proposals. env.toml drops its version key so
monolith output stays at 0.
@winder winder force-pushed the will/devenv-phased-no-cfg branch from e9dc852 to aa2bb20 Compare June 2, 2026 16:18
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

Code coverage report:

Package main will/devenv-phased-no-cfg Diff
github.com/smartcontractkit/chainlink-ccv/aggregator 49.35% 49.35% +0.00%
github.com/smartcontractkit/chainlink-ccv/bootstrap 54.14% 54.14% +0.00%
github.com/smartcontractkit/chainlink-ccv/cli 65.13% 65.13% +0.00%
github.com/smartcontractkit/chainlink-ccv/cmd 15.54% 15.54% +0.00%
github.com/smartcontractkit/chainlink-ccv/common 56.54% 56.54% +0.00%
github.com/smartcontractkit/chainlink-ccv/executor 45.97% 45.97% +0.00%
github.com/smartcontractkit/chainlink-ccv/indexer 37.68% 37.73% +0.05%
github.com/smartcontractkit/chainlink-ccv/integration 46.23% 46.13% -0.10%
github.com/smartcontractkit/chainlink-ccv/pkg 84.62% 84.62% +0.00%
github.com/smartcontractkit/chainlink-ccv/pricer 0.00% 0.00% +0.00%
github.com/smartcontractkit/chainlink-ccv/protocol 63.06% 63.06% +0.00%
github.com/smartcontractkit/chainlink-ccv/verifier 34.48% 34.48% +0.00%
Total 46.60% 46.50% -0.10%

@winder winder marked this pull request as ready for review June 2, 2026 16:22
@winder winder requested a review from a team as a code owner June 2, 2026 16:22
Copilot AI review requested due to automatic review settings June 2, 2026 16:22
@winder winder requested a review from a team as a code owner June 2, 2026 16:22
Comment thread build/devenv/config.go
Comment on lines +122 to +127
switch probe.Version {
case 0:
c, err = loadLegacyCfg(data)
case 1:
c, err = loadPhasedCfg(data)
default:
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I see why you might want a constant, but this (hopefully) goes away eventually. If we keep legacy around for an extended duration this probably changes to "version == 0 { legacy } else { phased }"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR changes the phased devenv output contract to serialize the raw component output map (with runtime-only _-prefixed keys stripped) and updates LoadOutput[Cfg] to be version-aware so downstream readers can load either legacy (monolith) or phased output through the same API.

Changes:

  • NewPhasedEnvironment now returns the accumulated output map and persists a stripped, raw-map output file for phased mode.
  • LoadOutput[Cfg] now dispatches decoding based on a top-level version marker (legacy strict decode vs phased lenient decode + derived endpoint maps).
  • Component output keys are reclassified into public vs _-private (e.g., environment_topology, _shared_tls_certs), and JD infra serialization is made TOML-safe.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
changelog/2026-05-29_phased_raw_output_versioned_load.md Documents the phased raw-output + versioned loader contract and breaking changes.
build/devenv/phased_loader_test.go Adds unit tests around phased decoding and output stripping behavior.
build/devenv/jobs/jd.go Makes JDInfrastructure serializable by tagging fields and excluding the live gRPC client.
build/devenv/environment_phased.go Switches phased env creation to persist the raw output map (minus _ keys) and return it.
build/devenv/env.toml Drops version from legacy env config so legacy output routes to version 0/absent behavior.
build/devenv/config.go Implements version-aware LoadOutput plus phased/legacy decode helpers.
build/devenv/components/protocol_contracts/component.go Publishes cldf and environment_topology as public outputs instead of _-prefixed keys.
build/devenv/components/indexer/component.go Updates indexer to consume _shared_tls_certs runtime-only key.
build/devenv/components/executor/component.go Updates executor to consume environment_topology public output key.
build/devenv/components/committeeccv/component.go Updates committeeccv outputs to use _shared_tls_certs and consumes environment_topology.
build/devenv/cli/ccv.go Adapts CLI env constructor handling to ignore return values consistently.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread build/devenv/config.go
Comment on lines +121 to +129
var c *Cfg
switch probe.Version {
case 0:
c, err = loadLegacyCfg(data)
case 1:
c, err = loadPhasedCfg(data)
default:
return nil, fmt.Errorf("unsupported output version %d; supported version is 1", probe.Version)
}
Comment on lines +30 to +35
// Capture the schema version before the runtime consumes and deletes the
// "version" key from rawConfig, so it can be re-emitted to the output file.
var version int
if v, ok := rawConfig["version"].(int64); ok {
version = int(v)
}
Comment on lines +79 to +103
// TestStorePhasedOutputStripsPrivateKeys verifies "_"-prefixed runtime keys are
// dropped from the serialized output and version is re-emitted as public.
func TestStorePhasedOutputStripsPrivateKeys(t *testing.T) {
out := map[string]any{
"version": 1,
"blockchains": []*blockchain.Input{{Type: "anvil"}},
"_env": "runtime-only",
"_shared_tls_certs": "runtime-only",
"environment_topology": map[string]any{"x": 1},
}

public := make(map[string]any, len(out))
for k, v := range out {
if k[0] == '_' {
continue
}
public[k] = v
}

_, hasEnv := public["_env"]
_, hasTLS := public["_shared_tls_certs"]
assert.False(t, hasEnv, "_env should be stripped")
assert.False(t, hasTLS, "_shared_tls_certs should be stripped")
assert.Contains(t, public, "blockchains")
assert.Contains(t, public, "environment_topology")
@winder winder added this pull request to the merge queue Jun 2, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 2, 2026
@winder winder added this pull request to the merge queue Jun 2, 2026
Merged via the queue into main with commit e16c167 Jun 2, 2026
37 checks passed
@winder winder deleted the will/devenv-phased-no-cfg branch June 2, 2026 17:26
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.

4 participants