diff --git a/cmd/harness/cli/agent_addons_install_integration_test.go b/cmd/harness/cli/agent_addons_install_integration_test.go index 1a58665..a998382 100644 --- a/cmd/harness/cli/agent_addons_install_integration_test.go +++ b/cmd/harness/cli/agent_addons_install_integration_test.go @@ -77,7 +77,7 @@ func TestHarnessInstallOrbitWithAgentAddonsReportsAgentAddonsAndMissingActivatio require.NoError(t, err) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) diff --git a/cmd/harness/cli/cli_integration_test.go b/cmd/harness/cli/cli_integration_test.go index bbb1acb..9651fc8 100644 --- a/cmd/harness/cli/cli_integration_test.go +++ b/cmd/harness/cli/cli_integration_test.go @@ -614,7 +614,7 @@ func TestHarnessAgentDeriveWritesRuntimeTruthFromInstalledBundleSnapshot(t *test bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -3459,7 +3459,7 @@ func TestHarnessCheckReportsDefinitionAndRuntimeFileDrift(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -3494,7 +3494,7 @@ func TestHarnessCheckReportsProvenanceUnresolvable(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -3580,7 +3580,7 @@ func TestHarnessBindingsMissingReportsCurrentVarsGapsAcrossInstallBackedOrbits(t { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -3593,7 +3593,7 @@ func TestHarnessBindingsMissingReportsCurrentVarsGapsAcrossInstallBackedOrbits(t { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -3621,7 +3621,7 @@ func TestHarnessBindingsMissingReportsCurrentVarsGapsAcrossInstallBackedOrbits(t require.NoError(t, err) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Filled Orbit\n") @@ -3702,7 +3702,7 @@ func TestHarnessBindingsMissingTextOutputMapsToReadinessReason(t *testing.T) { { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -3740,7 +3740,7 @@ func TestHarnessBindingsScanRuntimeReportsObservedPlaceholdersAndWritesInstallSn { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -3828,7 +3828,7 @@ func TestHarnessBindingsScanRuntimeTextOutputMapsToReadinessReason(t *testing.T) { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -3871,7 +3871,7 @@ func TestHarnessBindingsApplyDryRunJSONUsesCurrentVarsWithoutMutatingRuntime(t * { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -3893,7 +3893,7 @@ func TestHarnessBindingsApplyDryRunJSONUsesCurrentVarsWithoutMutatingRuntime(t * require.NoError(t, err) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Filled Orbit\n") @@ -3950,7 +3950,7 @@ func TestHarnessBindingsApplyWritesRenderedRuntimeAndRefreshesInstallSnapshot(t { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -3978,7 +3978,7 @@ func TestHarnessBindingsApplyWritesRenderedRuntimeAndRefreshesInstallSnapshot(t require.NoError(t, err) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Filled Orbit\n") @@ -4048,7 +4048,7 @@ func TestHarnessBindingsApplyAllowsUnresolvedBindingsAsWarnings(t *testing.T) { { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4119,7 +4119,7 @@ func TestHarnessBindingsApplyTextOutputIncludesReadinessStatus(t *testing.T) { { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4161,7 +4161,7 @@ func TestHarnessBindingsApplyFailsClosedOnDriftWithoutForceAndForceRewritesInsta { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4182,7 +4182,7 @@ func TestHarnessBindingsApplyFailsClosedOnDriftWithoutForceAndForceRewritesInsta require.NoError(t, err) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Filled Orbit\n") @@ -4240,7 +4240,7 @@ func TestHarnessBindingsApplyFailsWhenInstalledVariableDeclarationBecomesIncompa { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4321,7 +4321,7 @@ func TestHarnessBindingsApplyReportsInvalidLocalVarsBeforeRemoteReplay(t *testin runtimeRepo := seedEmptyHarnessRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Remote Installed Orbit\n"), 0o600)) @@ -4336,7 +4336,7 @@ func TestHarnessBindingsApplyReportsInvalidLocalVarsBeforeRemoteReplay(t *testin require.NoError(t, err) runtimeRepo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {\n"+ " github_token: ${{ secrets.GITHUB_TOKEN }}\n"+ "}\n") @@ -4658,7 +4658,7 @@ func TestHarnessBindingsPlanJSONMergesLocalTemplateVariablesAndPrefillsRepoValue { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4670,7 +4670,7 @@ func TestHarnessBindingsPlanJSONMergesLocalTemplateVariablesAndPrefillsRepoValue { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4683,7 +4683,7 @@ func TestHarnessBindingsPlanJSONMergesLocalTemplateVariablesAndPrefillsRepoValue }, }, }, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -4726,7 +4726,7 @@ func TestHarnessBindingsPlanJSONMergesLocalTemplateVariablesAndPrefillsRepoValue require.Len(t, payload.Sources, 2) require.Equal(t, []string{"project_name"}, payload.ReusedValues) require.Equal(t, []string{"binary_name"}, payload.MissingRequired) - require.Equal(t, 1, payload.Bindings.SchemaVersion) + require.Equal(t, bindings.VarsSchemaVersion, payload.Bindings.SchemaVersion) require.Equal(t, "Orbit", payload.Bindings.Variables["project_name"].Value) require.Equal(t, "Product title", payload.Bindings.Variables["project_name"].Description) require.Empty(t, payload.Bindings.Variables["binary_name"].Value) @@ -4740,7 +4740,7 @@ func TestHarnessBindingsPlanNamespacesVariableDescriptionConflict(t *testing.T) { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4752,7 +4752,7 @@ func TestHarnessBindingsPlanNamespacesVariableDescriptionConflict(t *testing.T) { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4762,7 +4762,7 @@ func TestHarnessBindingsPlanNamespacesVariableDescriptionConflict(t *testing.T) }, }, }, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") stdout, stderr, err := executeHarnessCLI( @@ -4803,7 +4803,7 @@ func TestHarnessBindingsPlanOutPreservesUnrelatedExistingVars(t *testing.T) { { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4815,7 +4815,7 @@ func TestHarnessBindingsPlanOutPreservesUnrelatedExistingVars(t *testing.T) { { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -4828,7 +4828,7 @@ func TestHarnessBindingsPlanOutPreservesUnrelatedExistingVars(t *testing.T) { }, }, }, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -4860,7 +4860,7 @@ func TestHarnessBindingsPlanOutPreservesUnrelatedExistingVars(t *testing.T) { file, err := harnesspkg.LoadVarsFile(repo.Root) require.NoError(t, err) require.Equal(t, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "binary_name": { Value: "", @@ -4893,7 +4893,7 @@ func TestHarnessBindingsPlanReportsInvalidLocalVarsBeforeRemoteResolution(t *tes repo := seedEmptyHarnessRuntimeRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {\n"+ " github_token: ${{ secrets.GITHUB_TOKEN }}\n"+ "}\n") @@ -5484,7 +5484,7 @@ func TestHarnessRemoveShrinksBundleBackedRuntimeMember(t *testing.T) { bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -5550,7 +5550,7 @@ func TestHarnessMemberExtractDetachedKeepsPayloadAndRemovesBundleOwnership(t *te bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -5654,7 +5654,7 @@ func TestHarnessMemberExtractDetachedRemovesSingleMemberBundleAgentsBlock(t *tes bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -5710,7 +5710,7 @@ func TestHarnessMemberExtractDetachedRejectsBundleWithSurvivingRootAgentsBlock(t bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -5748,7 +5748,7 @@ func TestHarnessMemberExtractToWritesInstallRecordAndRehomesMember(t *testing.T) bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -5841,7 +5841,7 @@ func TestHarnessMemberExtractToRejectsDetachedHead(t *testing.T) { bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -5881,7 +5881,7 @@ func TestHarnessMemberExtractReuseOriginFailsWithoutHint(t *testing.T) { bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -5918,7 +5918,7 @@ func TestHarnessMemberExtractReuseOriginRestoresInstallOrbit(t *testing.T) { bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -5997,7 +5997,7 @@ func TestHarnessMemberExtractReuseOriginRejectsExternalGitHint(t *testing.T) { bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -6045,7 +6045,7 @@ func TestHarnessMemberExtractToRollsBackSavedBranchOnMutationFailure(t *testing. bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -6102,7 +6102,7 @@ func TestHarnessMemberExtractReuseOriginRollsBackSavedBranchOnMutationFailure(t bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -6418,7 +6418,7 @@ func TestHarnessInstallLocalTemplateWritesInstallRecordVarsAndMember(t *testing. repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -6461,7 +6461,7 @@ func TestHarnessInstallLocalTemplateRollsBackWhenLateWriteFails(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -6522,7 +6522,7 @@ func TestHarnessInstallTextOutputContract(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -6605,7 +6605,7 @@ func TestHarnessInstallTreatsBlankRepoVarAsUnresolved(t *testing.T) { repo := seedHarnessInstallRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: \" \"\n"+ @@ -6662,7 +6662,7 @@ func TestHarnessInstallPlainProgressWritesStagesToStderr(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -6692,7 +6692,7 @@ func TestHarnessInstallPlainProgressPreservesJSONStdout(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -6719,7 +6719,7 @@ func TestHarnessInstallQuietProgressSuppressesStages(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -6744,7 +6744,7 @@ func TestHarnessInstallDryRunJSONIncludesRuntimeWriteAndDoesNotMutateRuntime(t * repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Preview Orbit\n"), 0o600)) @@ -6785,7 +6785,7 @@ func TestHarnessInstallFailsWhenOrbitAlreadyInstalled(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -6808,7 +6808,7 @@ func TestHarnessInstallBatchDryRunJSONAggregatesMultipleOrbitPreviews(t *testing { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -6820,7 +6820,7 @@ func TestHarnessInstallBatchDryRunJSONAggregatesMultipleOrbitPreviews(t *testing { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -6835,7 +6835,7 @@ func TestHarnessInstallBatchDryRunJSONAggregatesMultipleOrbitPreviews(t *testing }) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Batch Orbit\n"+ @@ -6907,7 +6907,7 @@ func TestHarnessInstallBatchInstallsAllItemsAfterSharedPreview(t *testing.T) { { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -6919,7 +6919,7 @@ func TestHarnessInstallBatchInstallsAllItemsAfterSharedPreview(t *testing.T) { { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -6934,7 +6934,7 @@ func TestHarnessInstallBatchInstallsAllItemsAfterSharedPreview(t *testing.T) { }) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Batch Orbit\n"+ @@ -7009,7 +7009,7 @@ func TestHarnessInstallBatchRollsBackSharedVarsAndEarlierItemsWhenLaterInstallFa { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7021,7 +7021,7 @@ func TestHarnessInstallBatchRollsBackSharedVarsAndEarlierItemsWhenLaterInstallFa { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7036,7 +7036,7 @@ func TestHarnessInstallBatchRollsBackSharedVarsAndEarlierItemsWhenLaterInstallFa }) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Batch Orbit\n"+ @@ -7101,7 +7101,7 @@ func TestHarnessInstallBatchDefaultsToUnresolvedBindingsAndWarnings(t *testing.T { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7113,7 +7113,7 @@ func TestHarnessInstallBatchDefaultsToUnresolvedBindingsAndWarnings(t *testing.T { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7181,7 +7181,7 @@ func TestHarnessInstallBatchStrictBindingsFailsOnMissingBindings(t *testing.T) { { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7193,7 +7193,7 @@ func TestHarnessInstallBatchStrictBindingsFailsOnMissingBindings(t *testing.T) { { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7233,7 +7233,7 @@ func TestHarnessInstallBatchNamespacesIncompatibleSharedVariableDeclarations(t * { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7245,7 +7245,7 @@ func TestHarnessInstallBatchNamespacesIncompatibleSharedVariableDeclarations(t * { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7329,7 +7329,7 @@ func TestHarnessInstallBatchFailsClosedBeforeWritingWhenOrbitIDsRepeat(t *testin { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -7341,7 +7341,7 @@ func TestHarnessInstallBatchFailsClosedBeforeWritingWhenOrbitIDsRepeat(t *testin }) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Batch Orbit\n"), 0o600)) @@ -7374,7 +7374,7 @@ func TestHarnessInstallBatchReportsInvalidLocalVarsBeforeRemoteResolution(t *tes repo := seedEmptyHarnessRuntimeRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {\n"+ " github_token: ${{ secrets.GITHUB_TOKEN }}\n"+ "}\n") @@ -7405,7 +7405,7 @@ func TestHarnessInstallRemoteTemplateWritesInstallRecordVarsAndMember(t *testing runtimeRepo := seedEmptyHarnessRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Remote Installed Orbit\n"), 0o600)) @@ -7454,7 +7454,7 @@ func TestHarnessInstallRemoteTemplateReportsInvalidLocalVarsBeforeRemoteResoluti repo := seedEmptyHarnessRuntimeRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {\n"+ " github_token: ${{ secrets.GITHUB_TOKEN }}\n"+ "}\n") @@ -7485,7 +7485,7 @@ func TestHarnessInstallRemoteWithoutRefReportsInvalidBindingsBeforeRemoteProgres repo := seedEmptyHarnessRuntimeRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {\n"+ " github_token: ${{ secrets.GITHUB_TOKEN }}\n"+ "}\n"), 0o600)) @@ -7517,7 +7517,7 @@ func TestHarnessInstallRemoteTemplateExplicitRefReportsLocalConflictBeforeFetch( repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -7551,7 +7551,7 @@ func TestHarnessInstallRemoteAliasRefReportsInvalidLocalVarsBeforeRemoteProgress repo := seedEmptyHarnessRuntimeRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {\n"+ " github_token: ${{ secrets.GITHUB_TOKEN }}\n"+ "}\n") @@ -7742,7 +7742,7 @@ func TestOrbitRuntimeCommandsWorkInCreatedRuntimeAfterFirstCommit(t *testing.T) runGitInDir(t, runtimeRoot, "config", "user.email", "orbit@example.com") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8011,7 +8011,7 @@ func TestHarnessInstallOverwriteExistingReplacesOwnedFilesAndUpdatesInstallRecor repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8075,7 +8075,7 @@ func TestHarnessInstallCrossInstallOverrideRequiresExplicitOverride(t *testing.T repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8111,7 +8111,7 @@ func TestHarnessInstallCrossInstallOverrideReplacesActiveInstallMember(t *testin repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8175,7 +8175,7 @@ func TestHarnessInstallHarnessTemplateOverrideActiveOrbitInstall(t *testing.T) { orbitBindingsPath := filepath.Join(runtimeRepo.Root, "orbit-bindings.yaml") require.NoError(t, os.WriteFile(orbitBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8184,7 +8184,7 @@ func TestHarnessInstallHarnessTemplateOverrideActiveOrbitInstall(t *testing.T) { harnessBindingsPath := filepath.Join(runtimeRepo.Root, "harness-bindings.yaml") require.NoError(t, os.WriteFile(harnessBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -8268,7 +8268,7 @@ func TestHarnessInstallOrbitTemplateOverrideBundleBackedMemberRequiresExplicitOv harnessBindingsPath := filepath.Join(runtimeRepo.Root, "harness-bindings.yaml") require.NoError(t, os.WriteFile(harnessBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -8281,7 +8281,7 @@ func TestHarnessInstallOrbitTemplateOverrideBundleBackedMemberRequiresExplicitOv orbitBindingsPath := filepath.Join(runtimeRepo.Root, "orbit-bindings.yaml") require.NoError(t, os.WriteFile(orbitBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8330,7 +8330,7 @@ func TestHarnessInstallHarnessTemplateOverrideBundleBackedMemberShrinksPreviousB initialBindingsPath := filepath.Join(runtimeRepo.Root, "initial-bindings.yaml") require.NoError(t, os.WriteFile(initialBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -8343,7 +8343,7 @@ func TestHarnessInstallHarnessTemplateOverrideBundleBackedMemberShrinksPreviousB replacementBindingsPath := filepath.Join(runtimeRepo.Root, "replacement-bindings.yaml") require.NoError(t, os.WriteFile(replacementBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -8435,7 +8435,7 @@ func TestHarnessInstallOrbitTemplateOverrideBundleBackedMemberShrinksPreviousBun harnessBindingsPath := filepath.Join(runtimeRepo.Root, "harness-bindings.yaml") require.NoError(t, os.WriteFile(harnessBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -8448,7 +8448,7 @@ func TestHarnessInstallOrbitTemplateOverrideBundleBackedMemberShrinksPreviousBun orbitBindingsPath := filepath.Join(runtimeRepo.Root, "orbit-bindings.yaml") require.NoError(t, os.WriteFile(orbitBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8523,7 +8523,7 @@ func TestHarnessInstallReinstallAfterRemoveIgnoresDetachedInstallRecord(t *testi repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8558,7 +8558,7 @@ func TestHarnessInstallBatchReinstallAfterRemoveIgnoresDetachedInstallRecord(t * repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8582,7 +8582,7 @@ func TestHarnessInstallOverwriteFailsWhenExistingOwnedFilesCannotBeSafelyReconst repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8630,7 +8630,7 @@ func TestHarnessInstallOverwriteFailsClosedWhenInstallRecordLacksVariablesSnapsh repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8675,7 +8675,7 @@ func TestHarnessBindingsMissingReportsSnapshotlessInstallRecord(t *testing.T) { repo := seedHarnessInstallRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -8947,7 +8947,7 @@ func TestHarnessInstallDryRunHarnessTemplateIgnoresStandaloneRuntimeVarsDescript runtimeRepo.Run(t, "fetch", "source", "harness-template/workspace:harness-template/workspace") _, err = harnesspkg.WriteVarsFile(runtimeRepo.Root, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "Orbit", @@ -9015,7 +9015,7 @@ func TestHarnessInstallDryRunHarnessTemplateConflictsOnInstalledOrbitVariableDec }) require.NoError(t, err) _, err = harnesspkg.WriteVarsFile(runtimeRepo.Root, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "Orbit", @@ -9052,7 +9052,7 @@ func TestHarnessInstallDryRunHarnessTemplateConflictsOnInstalledBundleVariableDe "include:\n"+ " - qa/**\n") conflictingRepo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -9076,7 +9076,7 @@ func TestHarnessInstallDryRunHarnessTemplateConflictsOnInstalledBundleVariableDe initialBindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(initialBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -9088,7 +9088,7 @@ func TestHarnessInstallDryRunHarnessTemplateConflictsOnInstalledBundleVariableDe require.NoError(t, err) _, err = harnesspkg.WriteVarsFile(runtimeRepo.Root, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "Installed Orbit", @@ -9297,7 +9297,7 @@ func TestHarnessInstallRemoteHarnessTemplateReportsInvalidBindingsBeforeRemoteRe repo := seedEmptyHarnessRuntimeRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {\n"+ " github_token: ${{ secrets.GITHUB_TOKEN }}\n"+ "}\n"), 0o600)) @@ -9329,7 +9329,7 @@ func TestHarnessInstallRemoteHarnessTemplateReportsInvalidLocalVarsBeforeRemoteR repo := seedEmptyHarnessRuntimeRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {\n"+ " github_token: ${{ secrets.GITHUB_TOKEN }}\n"+ "}\n") @@ -9384,7 +9384,7 @@ func TestHarnessInstallDryRunHarnessTemplateUsesRenderedContentForPathConflictAn bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -9419,7 +9419,7 @@ func TestHarnessInstallHarnessTemplateLocalWriteJSON(t *testing.T) { bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -9529,7 +9529,7 @@ func TestHarnessInstallHarnessTemplateOverwriteExistingReplacesSameBundle(t *tes initialBindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(initialBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -9561,7 +9561,7 @@ func TestHarnessInstallHarnessTemplateOverwriteExistingReplacesSameBundle(t *tes overwriteBindingsPath := filepath.Join(runtimeRepo.Root, "overwrite-bindings.yaml") require.NoError(t, os.WriteFile(overwriteBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -9645,7 +9645,7 @@ func TestHarnessInstallHarnessTemplateOverwriteExistingFailsAcrossInstallUnits(t initialBindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") require.NoError(t, os.WriteFile(initialBindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"+ @@ -10028,7 +10028,7 @@ func TestHarnessTemplateSaveOverwriteRewritesExistingBranch(t *testing.T) { func TestHarnessTemplateSaveEditTemplateWritesEditedTemplateWithoutMutatingRuntimeWorktree(t *testing.T) { repo := seedHarnessTemplateSaveRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -10086,7 +10086,7 @@ func TestHarnessTemplateSaveFailsClosedOnReplacementAmbiguity(t *testing.T) { repo := seedHarnessTemplateSaveRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " product_name:\n"+ " value: Orbit\n"+ @@ -10117,7 +10117,7 @@ func TestHarnessTemplateSaveJSONFailureIncludesAmbiguityContributors(t *testing. repo := seedHarnessTemplateSaveRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " product_name:\n"+ " value: Orbit\n"+ @@ -10196,7 +10196,7 @@ func TestHarnessTemplateSaveDryRunJSONIncludesAmbiguityContributors(t *testing.T repo := seedHarnessTemplateSaveRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " product_name:\n"+ " value: Orbit\n"+ @@ -10275,7 +10275,7 @@ func seedHarnessInstallRepo(t *testing.T) *testutil.Repo { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -10315,7 +10315,7 @@ func seedHarnessAgentsComposeRepo(t *testing.T) *testutil.Repo { require.NoError(t, err) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n"+ @@ -10574,7 +10574,7 @@ func seedHarnessTemplateSaveRepo(t *testing.T) *testutil.Repo { "include:\n"+ " - cmd/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -10617,7 +10617,7 @@ func seedHarnessTemplateSaveRepoWithoutAgents(t *testing.T) *testutil.Repo { "include:\n"+ " - cmd/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -10651,7 +10651,7 @@ func seedSingleMemberHarnessTemplateSaveRepo(t *testing.T, withAgents bool) *tes "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/harness/cli/commands/bindings_plan.go b/cmd/harness/cli/commands/bindings_plan.go index 09f6261..464450f 100644 --- a/cmd/harness/cli/commands/bindings_plan.go +++ b/cmd/harness/cli/commands/bindings_plan.go @@ -201,7 +201,7 @@ func buildBindingsPlanPreviews( func loadOptionalBindingsPlanRepoVars(ctx context.Context, repoRoot string) (bindings.VarsFile, error) { empty := bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, } diff --git a/cmd/harness/cli/commands/install_batch.go b/cmd/harness/cli/commands/install_batch.go index 49f04fc..3b4c041 100644 --- a/cmd/harness/cli/commands/install_batch.go +++ b/cmd/harness/cli/commands/install_batch.go @@ -520,7 +520,7 @@ func failOnBlockingBatchConflicts(candidates []orbitInstallBatchCandidate, overw func buildBatchVarsFile(repoRoot string, candidates []orbitInstallBatchCandidate) (bindings.VarsFile, bool, error) { existing := bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, } hasExisting := false @@ -581,7 +581,7 @@ func buildBatchVarsFile(repoRoot string, candidates []orbitInstallBatchCandidate } planned := bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: merged, } if len(scopedMerged) > 0 { diff --git a/cmd/harness/cli/commands/install_guidance_failure_command_test.go b/cmd/harness/cli/commands/install_guidance_failure_command_test.go index 812de1b..f24efdb 100644 --- a/cmd/harness/cli/commands/install_guidance_failure_command_test.go +++ b/cmd/harness/cli/commands/install_guidance_failure_command_test.go @@ -177,7 +177,7 @@ func seedInstallGuidanceCommandRepo(t *testing.T, templates []installGuidanceCom for _, template := range templates { repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -232,7 +232,7 @@ func writeInstallGuidanceCommandBindings(t *testing.T, repoRoot string) string { bindingsPath := filepath.Join(repoRoot, "install-guidance-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) diff --git a/cmd/harness/cli/commands/install_transaction_test.go b/cmd/harness/cli/commands/install_transaction_test.go index 36f0294..e76deb9 100644 --- a/cmd/harness/cli/commands/install_transaction_test.go +++ b/cmd/harness/cli/commands/install_transaction_test.go @@ -20,7 +20,7 @@ func TestInstallOverwriteRollsBackWhenCleanupFails(t *testing.T) { repo := seedInstallCommandRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -92,7 +92,7 @@ func TestInstallBatchOverwriteRollsBackWhenCleanupFails(t *testing.T) { repo := seedInstallCommandRepo(t) bindingsPath := filepath.Join(repo.Root, "install-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) @@ -253,7 +253,7 @@ func seedInstallCommandRepo(t *testing.T) *testutil.Repo { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/harness/cli/install_guidance_compose_integration_test.go b/cmd/harness/cli/install_guidance_compose_integration_test.go index 0d54d11..56e854d 100644 --- a/cmd/harness/cli/install_guidance_compose_integration_test.go +++ b/cmd/harness/cli/install_guidance_compose_integration_test.go @@ -396,7 +396,7 @@ func seedHarnessInstallGuidanceRepo(t *testing.T, templates []installGuidanceTem for _, template := range templates { repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -451,7 +451,7 @@ func writeHarnessInstallGuidanceBindings(t *testing.T, repoRoot string) string { bindingsPath := filepath.Join(repoRoot, "install-guidance-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Installed Orbit\n"), 0o600)) diff --git a/cmd/harness/cli/progress_integration_test.go b/cmd/harness/cli/progress_integration_test.go index 0ec21f5..cb4acea 100644 --- a/cmd/harness/cli/progress_integration_test.go +++ b/cmd/harness/cli/progress_integration_test.go @@ -44,7 +44,7 @@ func TestHarnessBindingsApplyPlainProgressPreservesJSONStdout(t *testing.T) { repo := seedInstalledHarnessProgressRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Filled Orbit\n") @@ -98,7 +98,7 @@ func TestHarnessBindingsPlanPlainProgressPreservesJSONStdout(t *testing.T) { { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -110,7 +110,7 @@ func TestHarnessBindingsPlanPlainProgressPreservesJSONStdout(t *testing.T) { { OrbitID: "cmd", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + @@ -123,7 +123,7 @@ func TestHarnessBindingsPlanPlainProgressPreservesJSONStdout(t *testing.T) { }, }, }, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -169,7 +169,7 @@ func seedInstalledHarnessProgressRepo(t *testing.T) *testutil.Repo { { OrbitID: "docs", VarsYAML: "" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + " project_name:\n" + " value: Orbit\n" + diff --git a/cmd/harness/cli/template_publish_integration_test.go b/cmd/harness/cli/template_publish_integration_test.go index 0ef9e7f..b27de91 100644 --- a/cmd/harness/cli/template_publish_integration_test.go +++ b/cmd/harness/cli/template_publish_integration_test.go @@ -535,7 +535,7 @@ func seedUncommittedHarnessTemplateSaveRepo(t *testing.T) *testutil.Repo { "include:\n"+ " - cmd/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/harness/cli/template_save_bootstrap_integration_test.go b/cmd/harness/cli/template_save_bootstrap_integration_test.go index 30c8388..5e155c2 100644 --- a/cmd/harness/cli/template_save_bootstrap_integration_test.go +++ b/cmd/harness/cli/template_save_bootstrap_integration_test.go @@ -144,7 +144,7 @@ func seedHarnessBootstrapTemplateSaveRepo(t *testing.T) *testutil.Repo { " include:\n"+ " - bootstrap/docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/hyard/cli/root.go b/cmd/hyard/cli/root.go index 7045a94..9d71e1d 100644 --- a/cmd/hyard/cli/root.go +++ b/cmd/hyard/cli/root.go @@ -57,6 +57,7 @@ func NewRootCommand() *cobra.Command { newRegistryCommand(), newPrepareCommand(), newBootstrapCommand(), + newVarsCommand(), newOrbitCommand(), newAssignCommand(), newUnassignCommand(), diff --git a/cmd/hyard/cli/vars.go b/cmd/hyard/cli/vars.go new file mode 100644 index 0000000..a2b09f2 --- /dev/null +++ b/cmd/hyard/cli/vars.go @@ -0,0 +1,99 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + harnesspkg "github.com/zack-nova/harnessyard/cmd/orbit/cli/harness" +) + +type varsPathOutput struct { + Path string `json:"path"` +} + +type varsValidateOutput struct { + Path string `json:"path"` + Valid bool `json:"valid"` +} + +func newVarsCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "vars", + Short: "Manage Runtime Bindings", + Long: "Manage Runtime Bindings for Package Variables.\n" + + "The canonical Runtime Bindings file is .harness/vars.yaml.", + Args: cobra.NoArgs, + } + + cmd.AddCommand( + newVarsPathCommand(), + newVarsValidateCommand(), + ) + + return cmd +} + +func newVarsPathCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "path", + Short: "Print the canonical Runtime Bindings path", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + jsonOutput, err := wantHyardJSON(cmd) + if err != nil { + return err + } + if jsonOutput { + return emitHyardJSON(cmd, varsPathOutput{Path: harnesspkg.VarsRepoPath()}) + } + + if _, err := fmt.Fprintf(cmd.OutOrStdout(), "%s\n", harnesspkg.VarsRepoPath()); err != nil { + return fmt.Errorf("write command output: %w", err) + } + + return nil + }, + } + addHyardJSONFlag(cmd) + + return cmd +} + +func newVarsValidateCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "validate", + Short: "Validate the canonical Runtime Bindings file", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + workingDir, err := hyardWorkingDirFromCommand(cmd) + if err != nil { + return err + } + resolved, err := harnesspkg.ResolveRoot(cmd.Context(), workingDir) + if err != nil { + return fmt.Errorf("resolve harness root: %w", err) + } + if err := harnesspkg.ValidateVarsFile(resolved.Repo.Root); err != nil { + return fmt.Errorf("validate Runtime Bindings file: %w", err) + } + + jsonOutput, err := wantHyardJSON(cmd) + if err != nil { + return err + } + if jsonOutput { + return emitHyardJSON(cmd, varsValidateOutput{Path: harnesspkg.VarsRepoPath(), Valid: true}) + } + + if _, err := fmt.Fprintf(cmd.OutOrStdout(), "validated Runtime Bindings file: %s\n", harnesspkg.VarsRepoPath()); err != nil { + return fmt.Errorf("write command output: %w", err) + } + + return nil + }, + } + addHyardJSONFlag(cmd) + + return cmd +} diff --git a/cmd/hyard/cli/vars_integration_test.go b/cmd/hyard/cli/vars_integration_test.go new file mode 100644 index 0000000..ca34b64 --- /dev/null +++ b/cmd/hyard/cli/vars_integration_test.go @@ -0,0 +1,63 @@ +package cli_test + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestHyardVarsPathReportsCanonicalRuntimeBindingsPath(t *testing.T) { + t.Parallel() + + repo := seedHyardRuntimeRepo(t) + + stdout, stderr, err := executeHyardCLI(t, repo.Root, "vars", "path") + require.NoError(t, err) + require.Empty(t, stderr) + require.Equal(t, ".harness/vars.yaml\n", stdout) +} + +func TestHyardVarsValidateAcceptsSchema2RuntimeBindings(t *testing.T) { + t.Parallel() + + repo := seedHyardRuntimeRepo(t) + repo.WriteFile(t, ".harness/vars.yaml", ""+ + "schema_version: 2\n"+ + "variables:\n"+ + " project_name:\n"+ + " value: Harness Yard\n"+ + " github_token:\n"+ + " value_from:\n"+ + " env: GITHUB_TOKEN\n"+ + "scoped_variables:\n"+ + " docs:\n"+ + " variables:\n"+ + " issue_payload:\n"+ + " value_from:\n"+ + " file: .harness/context/issue.json\n") + + stdout, stderr, err := executeHyardCLI(t, repo.Root, "vars", "validate") + require.NoError(t, err) + require.Empty(t, stderr) + require.Equal(t, "validated Runtime Bindings file: .harness/vars.yaml\n", stdout) +} + +func TestHyardVarsValidateReportsActionableRuntimeBindingsErrors(t *testing.T) { + t.Parallel() + + repo := seedHyardRuntimeRepo(t) + repo.WriteFile(t, ".harness/vars.yaml", ""+ + "schema_version: 2\n"+ + "variables:\n"+ + " project_name:\n"+ + " value: Harness Yard\n"+ + " value_from:\n"+ + " env: PROJECT_NAME\n") + + stdout, stderr, err := executeHyardCLI(t, repo.Root, "vars", "validate") + require.Error(t, err) + require.Empty(t, stdout) + require.Empty(t, stderr) + require.ErrorContains(t, err, ".harness/vars.yaml") + require.ErrorContains(t, err, "variables.project_name must set exactly one of value or value_from") +} diff --git a/cmd/orbit/cli/bindings/vars.go b/cmd/orbit/cli/bindings/vars.go index 37a4cf3..d5c597f 100644 --- a/cmd/orbit/cli/bindings/vars.go +++ b/cmd/orbit/cli/bindings/vars.go @@ -15,8 +15,9 @@ import ( ) const ( - varsRelativePath = ".orbit/vars.yaml" - varsSchemaVersion = 1 + varsRelativePath = ".harness/vars.yaml" + VarsSchemaVersion = 2 + varsSchemaVersion = VarsSchemaVersion variablesFieldName = "variables" scopedVariablesFieldName = "scoped_variables" scopedVariablesNestedName = "variables" @@ -36,8 +37,15 @@ type ScopedVariableBindings struct { // VariableBinding stores a concrete string value and optional description. type VariableBinding struct { - Value string `yaml:"value"` - Description string `yaml:"description,omitempty"` + Value string `yaml:"value,omitempty"` + ValueFrom *ValueSource `yaml:"value_from,omitempty"` + Description string `yaml:"description,omitempty"` +} + +// ValueSource stores one explicit source for a Runtime Binding value. +type ValueSource struct { + Env string `yaml:"env,omitempty"` + File string `yaml:"file,omitempty"` } // ScopedVariablesForNamespace returns the variable map for one namespace, if present. @@ -63,24 +71,27 @@ type rawScopedVariableBindings struct { } type rawVariableBinding struct { - Value *string `yaml:"value"` - Description *string `yaml:"description"` + Value *string `yaml:"value"` + ValueFrom *rawValueSource `yaml:"value_from"` + Description *string `yaml:"description"` + NotMapping bool `yaml:"-"` } -// UnmarshalYAML accepts both the canonical mapping form and a scalar shorthand. +type rawValueSource struct { + Env *string `yaml:"env"` + File *string `yaml:"file"` + NotMapping bool `yaml:"-"` +} + +// UnmarshalYAML records scalar shorthand so validation can report the binding path. func (raw *rawVariableBinding) UnmarshalYAML(node *yaml.Node) error { switch node.Kind { case yaml.ScalarNode: - if node.Tag == "!!null" { - return nil - } - - value := node.Value - raw.Value = &value - raw.Description = nil + raw.NotMapping = true return nil case yaml.MappingNode: var value *string + var valueFrom *rawValueSource var description *string for index := 0; index < len(node.Content); index += 2 { key := node.Content[index].Value @@ -93,6 +104,12 @@ func (raw *rawVariableBinding) UnmarshalYAML(node *yaml.Node) error { return fmt.Errorf("decode value: %w", err) } value = &decoded + case "value_from": + var decoded rawValueSource + if err := valueNode.Decode(&decoded); err != nil { + return fmt.Errorf("decode value_from: %w", err) + } + valueFrom = &decoded case "description": var decoded string if err := valueNode.Decode(&decoded); err != nil { @@ -105,19 +122,61 @@ func (raw *rawVariableBinding) UnmarshalYAML(node *yaml.Node) error { } raw.Value = value + raw.ValueFrom = valueFrom raw.Description = description + raw.NotMapping = false return nil default: return fmt.Errorf("cannot unmarshal %s into bindings.rawVariableBinding", node.ShortTag()) } } -// VarsPath returns the absolute path to .orbit/vars.yaml. +// UnmarshalYAML records invalid source shapes so validation can report the binding path. +func (raw *rawValueSource) UnmarshalYAML(node *yaml.Node) error { + switch node.Kind { + case yaml.ScalarNode: + raw.NotMapping = true + return nil + case yaml.MappingNode: + var env *string + var file *string + for index := 0; index < len(node.Content); index += 2 { + key := node.Content[index].Value + valueNode := node.Content[index+1] + + switch key { + case "env": + var decoded string + if err := valueNode.Decode(&decoded); err != nil { + return fmt.Errorf("decode env: %w", err) + } + env = &decoded + case "file": + var decoded string + if err := valueNode.Decode(&decoded); err != nil { + return fmt.Errorf("decode file: %w", err) + } + file = &decoded + default: + return fmt.Errorf("field %q not found in type bindings.rawValueSource", key) + } + } + + raw.Env = env + raw.File = file + raw.NotMapping = false + return nil + default: + return fmt.Errorf("cannot unmarshal %s into bindings.rawValueSource", node.ShortTag()) + } +} + +// VarsPath returns the absolute path to .harness/vars.yaml. func VarsPath(repoRoot string) string { return filepath.Join(repoRoot, filepath.FromSlash(varsRelativePath)) } -// LoadVarsFile reads, decodes, and validates the bindings file at the fixed Phase 2 host path. +// LoadVarsFile reads, decodes, and validates the bindings file at the canonical Runtime Bindings path. func LoadVarsFile(repoRoot string) (VarsFile, error) { return LoadVarsFileAtPath(VarsPath(repoRoot)) } @@ -138,7 +197,7 @@ func LoadVarsFileAtPath(filename string) (VarsFile, error) { return file, nil } -// LoadVarsFileWorktreeOrHEAD reads the bindings file from the fixed Phase 2 host path. +// LoadVarsFileWorktreeOrHEAD reads the bindings file from the canonical Runtime Bindings path. func LoadVarsFileWorktreeOrHEAD(ctx context.Context, repoRoot string) (VarsFile, error) { return LoadVarsFileWorktreeOrHEADAtRepoPath(ctx, repoRoot, varsRelativePath) } @@ -160,7 +219,7 @@ func LoadVarsFileWorktreeOrHEADAtRepoPath(ctx context.Context, repoRoot string, return file, nil } -// ParseVarsData decodes and validates .orbit/vars.yaml bytes. +// ParseVarsData decodes and validates Runtime Bindings bytes. func ParseVarsData(data []byte) (VarsFile, error) { var raw rawVarsFile if err := contractutil.DecodeKnownFields(data, &raw); err != nil { @@ -197,6 +256,9 @@ func ValidateVarsFile(file VarsFile) error { if err := contractutil.ValidateVariableName(name); err != nil { return fmt.Errorf("variables.%s: %w", name, err) } + if err := validateVariableBinding(fmt.Sprintf("variables.%s", name), file.Variables[name]); err != nil { + return err + } } for _, namespace := range contractutil.SortedKeys(file.ScopedVariables) { if err := ids.ValidateOrbitID(namespace); err != nil { @@ -210,13 +272,19 @@ func ValidateVarsFile(file VarsFile) error { if err := contractutil.ValidateVariableName(name); err != nil { return fmt.Errorf("%s.%s.%s.%s: %w", scopedVariablesFieldName, namespace, scopedVariablesNestedName, name, err) } + if err := validateVariableBinding( + fmt.Sprintf("%s.%s.%s.%s", scopedVariablesFieldName, namespace, scopedVariablesNestedName, name), + scoped.Variables[name], + ); err != nil { + return err + } } } return nil } -// WriteVarsFile validates and writes the bindings file at the fixed Phase 2 host path. +// WriteVarsFile validates and writes the bindings file at the canonical Runtime Bindings path. func WriteVarsFile(repoRoot string, file VarsFile) (string, error) { return WriteVarsFileAtPath(VarsPath(repoRoot), file) } @@ -299,12 +367,22 @@ func (raw rawVarsFile) toVarsFile() (VarsFile, error) { } func (raw rawVariableBinding) toVariableBinding(prefix string) (VariableBinding, error) { - if raw.Value == nil { - return VariableBinding{}, fmt.Errorf("%s.value must be present", prefix) + if raw.NotMapping { + return VariableBinding{}, fmt.Errorf("%s must be a mapping with value or value_from", prefix) + } + if (raw.Value == nil) == (raw.ValueFrom == nil) { + return VariableBinding{}, fmt.Errorf("%s must set exactly one of value or value_from", prefix) } - binding := VariableBinding{ - Value: *raw.Value, + binding := VariableBinding{} + if raw.Value != nil { + binding.Value = *raw.Value + } else { + valueFrom, err := raw.ValueFrom.toValueSource(prefix + ".value_from") + if err != nil { + return VariableBinding{}, err + } + binding.ValueFrom = &valueFrom } if raw.Description != nil { binding.Description = *raw.Description @@ -313,6 +391,55 @@ func (raw rawVariableBinding) toVariableBinding(prefix string) (VariableBinding, return binding, nil } +func (raw rawValueSource) toValueSource(prefix string) (ValueSource, error) { + if raw.NotMapping { + return ValueSource{}, fmt.Errorf("%s must be a mapping with env or file", prefix) + } + + hasEnv := raw.Env != nil + hasFile := raw.File != nil + if hasEnv == hasFile { + return ValueSource{}, fmt.Errorf("%s must set exactly one of env or file", prefix) + } + if hasEnv { + if strings.TrimSpace(*raw.Env) == "" { + return ValueSource{}, fmt.Errorf("%s.env must not be blank", prefix) + } + return ValueSource{Env: *raw.Env}, nil + } + if strings.TrimSpace(*raw.File) == "" { + return ValueSource{}, fmt.Errorf("%s.file must not be blank", prefix) + } + return ValueSource{File: *raw.File}, nil +} + +func validateVariableBinding(prefix string, binding VariableBinding) error { + if binding.ValueFrom == nil { + return nil + } + if binding.Value != "" { + return fmt.Errorf("%s must set exactly one of value or value_from", prefix) + } + + return validateValueSource(prefix+".value_from", *binding.ValueFrom) +} + +func validateValueSource(prefix string, source ValueSource) error { + hasEnv := source.Env != "" + hasFile := source.File != "" + if hasEnv == hasFile { + return fmt.Errorf("%s must set exactly one of env or file", prefix) + } + if hasEnv && strings.TrimSpace(source.Env) == "" { + return fmt.Errorf("%s.env must not be blank", prefix) + } + if hasFile && strings.TrimSpace(source.File) == "" { + return fmt.Errorf("%s.file must not be blank", prefix) + } + + return nil +} + func varsFileNode(file VarsFile) *yaml.Node { root := contractutil.MappingNode() contractutil.AppendMapping(root, "schema_version", contractutil.IntNode(file.SchemaVersion)) @@ -320,12 +447,7 @@ func varsFileNode(file VarsFile) *yaml.Node { variables := contractutil.MappingNode() for _, name := range contractutil.SortedKeys(file.Variables) { binding := file.Variables[name] - bindingNode := contractutil.MappingNode() - contractutil.AppendMapping(bindingNode, "value", contractutil.StringNode(binding.Value)) - if binding.Description != "" { - contractutil.AppendMapping(bindingNode, "description", contractutil.StringNode(binding.Description)) - } - contractutil.AppendMapping(variables, name, bindingNode) + contractutil.AppendMapping(variables, name, variableBindingNode(binding)) } contractutil.AppendMapping(root, variablesFieldName, variables) @@ -337,12 +459,7 @@ func varsFileNode(file VarsFile) *yaml.Node { variablesNode := contractutil.MappingNode() for _, name := range contractutil.SortedKeys(scoped.Variables) { binding := scoped.Variables[name] - bindingNode := contractutil.MappingNode() - contractutil.AppendMapping(bindingNode, "value", contractutil.StringNode(binding.Value)) - if binding.Description != "" { - contractutil.AppendMapping(bindingNode, "description", contractutil.StringNode(binding.Description)) - } - contractutil.AppendMapping(variablesNode, name, bindingNode) + contractutil.AppendMapping(variablesNode, name, variableBindingNode(binding)) } contractutil.AppendMapping(namespaceNode, scopedVariablesNestedName, variablesNode) contractutil.AppendMapping(scopedVariables, namespace, namespaceNode) @@ -352,3 +469,29 @@ func varsFileNode(file VarsFile) *yaml.Node { return root } + +func variableBindingNode(binding VariableBinding) *yaml.Node { + bindingNode := contractutil.MappingNode() + if binding.ValueFrom != nil { + contractutil.AppendMapping(bindingNode, "value_from", valueSourceNode(*binding.ValueFrom)) + } else { + contractutil.AppendMapping(bindingNode, "value", contractutil.StringNode(binding.Value)) + } + if binding.Description != "" { + contractutil.AppendMapping(bindingNode, "description", contractutil.StringNode(binding.Description)) + } + + return bindingNode +} + +func valueSourceNode(source ValueSource) *yaml.Node { + sourceNode := contractutil.MappingNode() + if source.Env != "" { + contractutil.AppendMapping(sourceNode, "env", contractutil.StringNode(source.Env)) + } + if source.File != "" { + contractutil.AppendMapping(sourceNode, "file", contractutil.StringNode(source.File)) + } + + return sourceNode +} diff --git a/cmd/orbit/cli/bindings/vars_test.go b/cmd/orbit/cli/bindings/vars_test.go index 733128a..b0a8fc8 100644 --- a/cmd/orbit/cli/bindings/vars_test.go +++ b/cmd/orbit/cli/bindings/vars_test.go @@ -8,30 +8,44 @@ import ( "github.com/stretchr/testify/require" ) -func TestParseVarsDataAllowsScalarShorthandBindings(t *testing.T) { +func TestParseVarsDataAcceptsSchema2Bindings(t *testing.T) { t.Parallel() file, err := ParseVarsData([]byte("" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables:\n" + - " github_token: '${{ secrets.GITHUB_TOKEN }}'\n" + + " project_name:\n" + + " value: Harness Yard\n" + + " github_token:\n" + + " value_from:\n" + + " env: GITHUB_TOKEN\n" + + " issue_payload:\n" + + " value_from:\n" + + " file: .harness/context/issue.json\n" + "scoped_variables:\n" + " docs:\n" + " variables:\n" + - " project_name: Docs Orbit\n")) + " project_name:\n" + + " value: Harness Yard Docs\n")) require.NoError(t, err) require.Equal(t, VarsFile{ - SchemaVersion: 1, + SchemaVersion: 2, Variables: map[string]VariableBinding{ "github_token": { - Value: "${{ secrets.GITHUB_TOKEN }}", + ValueFrom: &ValueSource{Env: "GITHUB_TOKEN"}, + }, + "issue_payload": { + ValueFrom: &ValueSource{File: ".harness/context/issue.json"}, + }, + "project_name": { + Value: "Harness Yard", }, }, ScopedVariables: map[string]ScopedVariableBindings{ "docs": { Variables: map[string]VariableBinding{ "project_name": { - Value: "Docs Orbit", + Value: "Harness Yard Docs", }, }, }, @@ -41,22 +55,28 @@ func TestParseVarsDataAllowsScalarShorthandBindings(t *testing.T) { data, err := MarshalVarsFile(file) require.NoError(t, err) require.Equal(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " github_token:\n"+ - " value: ${{ secrets.GITHUB_TOKEN }}\n"+ + " value_from:\n"+ + " env: GITHUB_TOKEN\n"+ + " issue_payload:\n"+ + " value_from:\n"+ + " file: .harness/context/issue.json\n"+ + " project_name:\n"+ + " value: Harness Yard\n"+ "scoped_variables:\n"+ " docs:\n"+ " variables:\n"+ " project_name:\n"+ - " value: Docs Orbit\n", string(data)) + " value: Harness Yard Docs\n", string(data)) } func TestParseVarsDataSuggestsHowToFixInlineGitHubActionsExpressions(t *testing.T) { t.Parallel() _, err := ParseVarsData([]byte("" + - "schema_version: 1\n" + + "schema_version: 2\n" + "variables: {\n" + " github_token: ${{ secrets.GITHUB_TOKEN }}\n" + "}\n")) @@ -71,12 +91,16 @@ func TestWriteAndLoadVarsFileRoundTrip(t *testing.T) { repoRoot := t.TempDir() input := VarsFile{ - SchemaVersion: 1, + SchemaVersion: 2, Variables: map[string]VariableBinding{ "service_url": { Value: "http://localhost:3000", Description: "Service URL", }, + "github_token": { + ValueFrom: &ValueSource{Env: "GITHUB_TOKEN"}, + Description: "GitHub token", + }, "project_name": { Value: "Orbit", Description: "Project name", @@ -88,6 +112,9 @@ func TestWriteAndLoadVarsFileRoundTrip(t *testing.T) { ScopedVariables: map[string]ScopedVariableBindings{ "docs": { Variables: map[string]VariableBinding{ + "config_path": { + ValueFrom: &ValueSource{File: ".harness/docs/config.json"}, + }, "project_name": { Value: "Docs Orbit", Description: "Docs title", @@ -99,15 +126,19 @@ func TestWriteAndLoadVarsFileRoundTrip(t *testing.T) { filename, err := WriteVarsFile(repoRoot, input) require.NoError(t, err) - require.Equal(t, filepath.Join(repoRoot, ".orbit", "vars.yaml"), filename) + require.Equal(t, filepath.Join(repoRoot, ".harness", "vars.yaml"), filename) data, err := os.ReadFile(filename) require.NoError(t, err) require.Equal(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " empty_description:\n"+ " value: \"\"\n"+ + " github_token:\n"+ + " value_from:\n"+ + " env: GITHUB_TOKEN\n"+ + " description: GitHub token\n"+ " project_name:\n"+ " value: Orbit\n"+ " description: Project name\n"+ @@ -117,6 +148,9 @@ func TestWriteAndLoadVarsFileRoundTrip(t *testing.T) { "scoped_variables:\n"+ " docs:\n"+ " variables:\n"+ + " config_path:\n"+ + " value_from:\n"+ + " file: .harness/docs/config.json\n"+ " project_name:\n"+ " value: Docs Orbit\n"+ " description: Docs title\n", string(data)) @@ -130,27 +164,27 @@ func TestLoadVarsFileRejectsMissingValueField(t *testing.T) { t.Parallel() repoRoot := t.TempDir() - filename := filepath.Join(repoRoot, ".orbit", "vars.yaml") + filename := filepath.Join(repoRoot, ".harness", "vars.yaml") require.NoError(t, os.MkdirAll(filepath.Dir(filename), 0o755)) require.NoError(t, os.WriteFile(filename, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " description: project title\n"), 0o600)) _, err := LoadVarsFile(repoRoot) require.Error(t, err) - require.ErrorContains(t, err, "variables.project_name.value") + require.ErrorContains(t, err, "variables.project_name must set exactly one of value or value_from") } func TestLoadVarsFileAllowsEmptyValueString(t *testing.T) { t.Parallel() repoRoot := t.TempDir() - filename := filepath.Join(repoRoot, ".orbit", "vars.yaml") + filename := filepath.Join(repoRoot, ".harness", "vars.yaml") require.NoError(t, os.MkdirAll(filepath.Dir(filename), 0o755)) require.NoError(t, os.WriteFile(filename, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: \"\"\n"), 0o600)) @@ -158,7 +192,7 @@ func TestLoadVarsFileAllowsEmptyValueString(t *testing.T) { loaded, err := LoadVarsFile(repoRoot) require.NoError(t, err) require.Equal(t, VarsFile{ - SchemaVersion: 1, + SchemaVersion: 2, Variables: map[string]VariableBinding{ "project_name": { Value: "", @@ -171,20 +205,119 @@ func TestLoadVarsFileAllowsEmptyVariablesMap(t *testing.T) { t.Parallel() repoRoot := t.TempDir() - filename := filepath.Join(repoRoot, ".orbit", "vars.yaml") + filename := filepath.Join(repoRoot, ".harness", "vars.yaml") require.NoError(t, os.MkdirAll(filepath.Dir(filename), 0o755)) require.NoError(t, os.WriteFile(filename, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n"), 0o600)) loaded, err := LoadVarsFile(repoRoot) require.NoError(t, err) require.Equal(t, VarsFile{ - SchemaVersion: 1, + SchemaVersion: 2, Variables: map[string]VariableBinding{}, }, loaded) } +func TestParseVarsDataRejectsInvalidSchema2Shapes(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + input string + contains string + }{ + { + name: "schema one", + input: "" + + "schema_version: 1\n" + + "variables: {}\n", + contains: "schema_version must be 2", + }, + { + name: "scalar shorthand", + input: "" + + "schema_version: 2\n" + + "variables:\n" + + " project_name: Harness Yard\n", + contains: "variables.project_name must be a mapping with value or value_from", + }, + { + name: "invalid variable name", + input: "" + + "schema_version: 2\n" + + "variables:\n" + + " bad-name:\n" + + " value: Harness Yard\n", + contains: "variables.bad-name", + }, + { + name: "invalid scoped namespace", + input: "" + + "schema_version: 2\n" + + "variables: {}\n" + + "scoped_variables:\n" + + " Bad Docs:\n" + + " variables:\n" + + " project_name:\n" + + " value: Harness Yard\n", + contains: "scoped_variables.Bad Docs", + }, + { + name: "value and value_from", + input: "" + + "schema_version: 2\n" + + "variables:\n" + + " project_name:\n" + + " value: Harness Yard\n" + + " value_from:\n" + + " env: PROJECT_NAME\n", + contains: "variables.project_name must set exactly one of value or value_from", + }, + { + name: "neither value nor value_from", + input: "" + + "schema_version: 2\n" + + "variables:\n" + + " project_name:\n" + + " description: Project title\n", + contains: "variables.project_name must set exactly one of value or value_from", + }, + { + name: "blank env value source", + input: "" + + "schema_version: 2\n" + + "variables:\n" + + " github_token:\n" + + " value_from:\n" + + " env: \" \"\n", + contains: "variables.github_token.value_from.env must not be blank", + }, + { + name: "blank file value source", + input: "" + + "schema_version: 2\n" + + "variables:\n" + + " issue_payload:\n" + + " value_from:\n" + + " file: \" \"\n", + contains: "variables.issue_payload.value_from.file must not be blank", + }, + } + + for _, testCase := range testCases { + testCase := testCase + + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + _, err := ParseVarsData([]byte(testCase.input)) + require.Error(t, err) + require.ErrorContains(t, err, testCase.contains) + }) + } +} + func TestValidateVarsFileRejectsInvalidContracts(t *testing.T) { t.Parallel() @@ -196,24 +329,24 @@ func TestValidateVarsFileRejectsInvalidContracts(t *testing.T) { { name: "schema version must be frozen", input: VarsFile{ - SchemaVersion: 2, + SchemaVersion: 1, Variables: map[string]VariableBinding{ "project_name": {Value: "Orbit"}, }, }, - contains: "schema_version must be 1", + contains: "schema_version must be 2", }, { name: "variables field must be present", input: VarsFile{ - SchemaVersion: 1, + SchemaVersion: 2, }, contains: "variables must be present", }, { name: "variable names must stay template-safe", input: VarsFile{ - SchemaVersion: 1, + SchemaVersion: 2, Variables: map[string]VariableBinding{ "bad-name": {Value: "Orbit"}, }, @@ -223,7 +356,7 @@ func TestValidateVarsFileRejectsInvalidContracts(t *testing.T) { { name: "scoped namespace must be orbit id safe", input: VarsFile{ - SchemaVersion: 1, + SchemaVersion: 2, Variables: map[string]VariableBinding{}, ScopedVariables: map[string]ScopedVariableBindings{ "Bad Docs": { @@ -238,7 +371,7 @@ func TestValidateVarsFileRejectsInvalidContracts(t *testing.T) { { name: "scoped variables field must be present", input: VarsFile{ - SchemaVersion: 1, + SchemaVersion: 2, Variables: map[string]VariableBinding{}, ScopedVariables: map[string]ScopedVariableBindings{ "docs": {}, @@ -246,6 +379,59 @@ func TestValidateVarsFileRejectsInvalidContracts(t *testing.T) { }, contains: "scoped_variables.docs.variables must be present", }, + { + name: "binding cannot use value and value_from", + input: VarsFile{ + SchemaVersion: 2, + Variables: map[string]VariableBinding{ + "project_name": { + Value: "Orbit", + ValueFrom: &ValueSource{Env: "PROJECT_NAME"}, + }, + }, + }, + contains: "variables.project_name must set exactly one of value or value_from", + }, + { + name: "value_from env must not be blank", + input: VarsFile{ + SchemaVersion: 2, + Variables: map[string]VariableBinding{ + "github_token": {ValueFrom: &ValueSource{Env: " "}}, + }, + }, + contains: "variables.github_token.value_from.env must not be blank", + }, + { + name: "value_from file must not be blank", + input: VarsFile{ + SchemaVersion: 2, + Variables: map[string]VariableBinding{ + "issue_payload": {ValueFrom: &ValueSource{File: " "}}, + }, + }, + contains: "variables.issue_payload.value_from.file must not be blank", + }, + { + name: "value_from must set exactly one source", + input: VarsFile{ + SchemaVersion: 2, + Variables: map[string]VariableBinding{ + "project_name": {ValueFrom: &ValueSource{}}, + }, + }, + contains: "variables.project_name.value_from must set exactly one of env or file", + }, + { + name: "value_from cannot set env and file", + input: VarsFile{ + SchemaVersion: 2, + Variables: map[string]VariableBinding{ + "project_name": {ValueFrom: &ValueSource{Env: "PROJECT_NAME", File: ".harness/name.txt"}}, + }, + }, + contains: "variables.project_name.value_from must set exactly one of env or file", + }, } for _, testCase := range testCases { diff --git a/cmd/orbit/cli/bindings_init_integration_test.go b/cmd/orbit/cli/bindings_init_integration_test.go index dbd35ce..0419804 100644 --- a/cmd/orbit/cli/bindings_init_integration_test.go +++ b/cmd/orbit/cli/bindings_init_integration_test.go @@ -21,7 +21,7 @@ func TestBindingsInitLocalBranchWritesSkeletonToStdout(t *testing.T) { require.NoError(t, err) require.Empty(t, stderr) require.Equal(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: \"\"\n"+ @@ -70,7 +70,7 @@ func TestBindingsInitRemoteGitWritesOutputFileAndJSON(t *testing.T) { require.Equal(t, "orbit-template/docs", payload.Source.Ref) require.NotEmpty(t, payload.Source.Commit) require.Equal(t, outputPath, payload.OutputPath) - require.Equal(t, 1, payload.Bindings.SchemaVersion) + require.Equal(t, bindings.VarsSchemaVersion, payload.Bindings.SchemaVersion) require.Empty(t, payload.Bindings.Variables["project_name"].Value) require.Equal(t, "Product title", payload.Bindings.Variables["project_name"].Description) @@ -79,7 +79,7 @@ func TestBindingsInitRemoteGitWritesOutputFileAndJSON(t *testing.T) { parsed, err := bindings.ParseVarsData(outputData) require.NoError(t, err) require.Equal(t, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "", diff --git a/cmd/orbit/cli/cli_integration_test.go b/cmd/orbit/cli/cli_integration_test.go index a1af4ab..a0b53cd 100644 --- a/cmd/orbit/cli/cli_integration_test.go +++ b/cmd/orbit/cli/cli_integration_test.go @@ -438,7 +438,7 @@ func TestOrbitBriefBackfillWritesCurrentOrbitBlockToHostedSpec(t *testing.T) { "members: []\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") @@ -560,7 +560,7 @@ func TestOrbitBriefBackfillReportsSkippedStatusWhenHostedTruthAlreadyMatches(t * " updated_at: 2026-04-07T00:00:00Z\n"+ "members: []\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") @@ -4113,7 +4113,7 @@ func seedBriefBackfillRevisionRepo(t *testing.T, revisionKind string) *testutil. } repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") @@ -4186,7 +4186,7 @@ func seedBriefMaterializeRevisionRepo(t *testing.T, revisionKind string, agentsT } repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") diff --git a/cmd/orbit/cli/guidance_integration_test.go b/cmd/orbit/cli/guidance_integration_test.go index 010b3d8..763d320 100644 --- a/cmd/orbit/cli/guidance_integration_test.go +++ b/cmd/orbit/cli/guidance_integration_test.go @@ -955,7 +955,7 @@ func seedOrbitGuidanceRevisionRepo(t *testing.T, agentsTemplate string, humansTe " updated_at: 2026-04-18T00:00:00Z\n"+ "members: []\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") diff --git a/cmd/orbit/cli/harness/agent_addons_install_test.go b/cmd/orbit/cli/harness/agent_addons_install_test.go index b40bc4c..a8d5e60 100644 --- a/cmd/orbit/cli/harness/agent_addons_install_test.go +++ b/cmd/orbit/cli/harness/agent_addons_install_test.go @@ -43,7 +43,7 @@ func TestBuildTemplateInstallPreviewSnapshotsPackageAgentAddons(t *testing.T) { require.NoError(t, err) bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") runtimeRepo.WriteFile(t, "bindings.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") diff --git a/cmd/orbit/cli/harness/bindings_diagnostics.go b/cmd/orbit/cli/harness/bindings_diagnostics.go index 30c751b..8f4c6a3 100644 --- a/cmd/orbit/cli/harness/bindings_diagnostics.go +++ b/cmd/orbit/cli/harness/bindings_diagnostics.go @@ -278,7 +278,7 @@ func loadOptionalBindingsDiagnosticsVars(ctx context.Context, repoRoot string) ( } if errors.Is(err, os.ErrNotExist) { return bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, }, nil } diff --git a/cmd/orbit/cli/harness/bindings_diagnostics_test.go b/cmd/orbit/cli/harness/bindings_diagnostics_test.go index c36fd30..2202d2b 100644 --- a/cmd/orbit/cli/harness/bindings_diagnostics_test.go +++ b/cmd/orbit/cli/harness/bindings_diagnostics_test.go @@ -31,7 +31,7 @@ func TestInspectMissingBindingsMarksObservedOptionalPlaceholder(t *testing.T) { }) require.NoError(t, err) _, err = WriteVarsFile(repoRoot, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, }) require.NoError(t, err) @@ -93,7 +93,7 @@ func TestInspectMissingBindingsReportsSnapshotlessInstallRecord(t *testing.T) { }) require.NoError(t, err) _, err = WriteVarsFile(repoRoot, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, }) require.NoError(t, err) @@ -142,7 +142,7 @@ func TestInspectMissingBindingsTreatsExplicitEmptySnapshotAsZeroVariableContract }) require.NoError(t, err) _, err = WriteVarsFile(repoRoot, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, }) require.NoError(t, err) diff --git a/cmd/orbit/cli/harness/bindings_plan_test.go b/cmd/orbit/cli/harness/bindings_plan_test.go index 3441c97..8740a00 100644 --- a/cmd/orbit/cli/harness/bindings_plan_test.go +++ b/cmd/orbit/cli/harness/bindings_plan_test.go @@ -56,7 +56,7 @@ func TestBuildBindingsPlanMergesPreviewsAndPrefillsRepoValues(t *testing.T) { }, }, }, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "Orbit", @@ -83,7 +83,7 @@ func TestBuildBindingsPlanMergesPreviewsAndPrefillsRepoValues(t *testing.T) { require.Equal(t, []string{"binary_name"}, result.MissingRequired) require.Equal(t, []string{"project_name"}, result.ReusedValues) require.Equal(t, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "binary_name": { Value: "", @@ -134,7 +134,7 @@ func TestBuildBindingsPlanNamespacesVariableDescriptionConflict(t *testing.T) { }, }, }, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "Orbit", @@ -212,7 +212,7 @@ func TestBuildBindingsPlanPreservesUnrelatedExistingBindings(t *testing.T) { }, }, }, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "github_token": { Value: "${{ secrets.GITHUB_TOKEN }}", @@ -239,7 +239,7 @@ func TestBuildBindingsPlanPreservesUnrelatedExistingBindings(t *testing.T) { require.Equal(t, []string{"binary_name"}, result.MissingRequired) require.Equal(t, []string{"project_name"}, result.ReusedValues) require.Equal(t, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "binary_name": { Value: "", diff --git a/cmd/orbit/cli/harness/guidance_compose_test.go b/cmd/orbit/cli/harness/guidance_compose_test.go index 80d0181..38b976d 100644 --- a/cmd/orbit/cli/harness/guidance_compose_test.go +++ b/cmd/orbit/cli/harness/guidance_compose_test.go @@ -66,7 +66,7 @@ func seedRuntimeGuidanceComposeRepo(t *testing.T) *testutil.Repo { require.NoError(t, err) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") diff --git a/cmd/orbit/cli/harness/readiness_test.go b/cmd/orbit/cli/harness/readiness_test.go index 760fa63..1b8bbd1 100644 --- a/cmd/orbit/cli/harness/readiness_test.go +++ b/cmd/orbit/cli/harness/readiness_test.go @@ -109,7 +109,7 @@ func TestEvaluateRuntimeReadinessInstallBackedOrbitWithMissingRequiredBindingsIs require.NoError(t, err) _, err = WriteVarsFile(repo.Root, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, }) require.NoError(t, err) diff --git a/cmd/orbit/cli/harness/root_agents_test.go b/cmd/orbit/cli/harness/root_agents_test.go index a05cc82..921ab35 100644 --- a/cmd/orbit/cli/harness/root_agents_test.go +++ b/cmd/orbit/cli/harness/root_agents_test.go @@ -16,7 +16,7 @@ func TestBuildRootAgentsTemplateFileAppliesWholeFileReplacementAndStripsRuntimeM repo := testutil.NewRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -76,7 +76,7 @@ func TestBuildRootAgentsTemplateFileReturnsEmptyWhenRootAgentsMissing(t *testing repo := testutil.NewRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") repo.AddAndCommit(t, "seed runtime repo without root agents") diff --git a/cmd/orbit/cli/harness/template_candidate.go b/cmd/orbit/cli/harness/template_candidate.go index 9d95d62..8a56d12 100644 --- a/cmd/orbit/cli/harness/template_candidate.go +++ b/cmd/orbit/cli/harness/template_candidate.go @@ -135,7 +135,7 @@ func loadOptionalTemplateCandidateVars(ctx context.Context, repoRoot string) (bi } if errors.Is(err, os.ErrNotExist) { return bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, }, nil } diff --git a/cmd/orbit/cli/harness/template_candidate_test.go b/cmd/orbit/cli/harness/template_candidate_test.go index 6299add..5b32924 100644 --- a/cmd/orbit/cli/harness/template_candidate_test.go +++ b/cmd/orbit/cli/harness/template_candidate_test.go @@ -159,7 +159,7 @@ func TestBuildTemplateMemberCandidateIgnoresHostedCompanionVariables(t *testing. "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") repo.WriteFile(t, "docs/guide.md", "Plain guide\n") repo.AddAndCommit(t, "seed runtime repo with hosted companion variable") @@ -190,7 +190,7 @@ func TestBuildTemplateMemberCandidateFailsWhenDefinitionMissing(t *testing.T) { " commit_append_trailer: true\n"+ " sparse_checkout_mode: no-cone\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") repo.AddAndCommit(t, "seed runtime repo without target definition") @@ -221,7 +221,7 @@ func seedTemplateCandidateRepo(t *testing.T) *testutil.Repo { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/orbit/cli/harness/template_install_preview.go b/cmd/orbit/cli/harness/template_install_preview.go index 8188bab..50f3144 100644 --- a/cmd/orbit/cli/harness/template_install_preview.go +++ b/cmd/orbit/cli/harness/template_install_preview.go @@ -1106,7 +1106,7 @@ func loadTemplateInstallLocalInputs(ctx context.Context, repoRoot string, bindin func loadOptionalTemplateInstallRepoVarsFile(ctx context.Context, repoRoot string) (bindings.VarsFile, bool, error) { empty := bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, } if _, err := os.Stat(VarsPath(repoRoot)); err == nil { @@ -1176,7 +1176,7 @@ func planTemplateInstallBindingsWrite( } planned := bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: merged, } if len(scopedMerged) > 0 { diff --git a/cmd/orbit/cli/harness/template_install_preview_test.go b/cmd/orbit/cli/harness/template_install_preview_test.go index cc0003f..146cf35 100644 --- a/cmd/orbit/cli/harness/template_install_preview_test.go +++ b/cmd/orbit/cli/harness/template_install_preview_test.go @@ -54,7 +54,7 @@ func TestBuildTemplateInstallPreviewAllowsUnresolvedRequiredBindings(t *testing. require.Equal(t, ManifestPath(runtimeRepo.Root), bootstrap.ManifestPath) bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") runtimeRepo.WriteFile(t, "bindings.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -243,7 +243,7 @@ func TestApplyTemplateInstallPreviewRollsBackWhenBundleRecordWriteFails(t *testi bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") runtimeRepo.WriteFile(t, "bindings.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -307,7 +307,7 @@ func TestApplyTemplateInstallPreviewRollsBackWhenBundleCleanupFails(t *testing.T bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") runtimeRepo.WriteFile(t, "bindings.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -415,7 +415,7 @@ func TestBuildTemplateInstallPreviewConflictsWhenStaleBundlePathDrifted(t *testi bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") runtimeRepo.WriteFile(t, "bindings.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -477,7 +477,7 @@ func TestBuildTemplateInstallPreviewConflictsWhenStaleBundleAgentsBlockDrifted(t bindingsPath := filepath.Join(runtimeRepo.Root, "bindings.yaml") runtimeRepo.WriteFile(t, "bindings.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") diff --git a/cmd/orbit/cli/harness/template_save_test.go b/cmd/orbit/cli/harness/template_save_test.go index b7fcdd9..9da37b0 100644 --- a/cmd/orbit/cli/harness/template_save_test.go +++ b/cmd/orbit/cli/harness/template_save_test.go @@ -413,7 +413,7 @@ func seedTemplateSaveRepo(t *testing.T) *testutil.Repo { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -460,7 +460,7 @@ func seedUncommittedTemplateSaveRepo(t *testing.T) *testutil.Repo { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/orbit/cli/harness/vars.go b/cmd/orbit/cli/harness/vars.go index bcd6cd5..65795da 100644 --- a/cmd/orbit/cli/harness/vars.go +++ b/cmd/orbit/cli/harness/vars.go @@ -3,6 +3,7 @@ package harness import ( "context" "fmt" + "os" "github.com/zack-nova/harnessyard/cmd/orbit/cli/bindings" ) @@ -28,6 +29,19 @@ func LoadVarsFileWorktreeOrHEAD(ctx context.Context, repoRoot string) (bindings. return file, nil } +// ValidateVarsFile reads and validates the canonical .harness/vars.yaml file. +func ValidateVarsFile(repoRoot string) error { + data, err := os.ReadFile(VarsPath(repoRoot)) + if err != nil { + return fmt.Errorf("read %s: %w", VarsRepoPath(), err) + } + if _, err := bindings.ParseVarsData(data); err != nil { + return fmt.Errorf("validate %s: %w", VarsRepoPath(), err) + } + + return nil +} + // WriteVarsFile validates and writes .harness/vars.yaml with stable field ordering. func WriteVarsFile(repoRoot string, file bindings.VarsFile) (string, error) { filename, err := bindings.WriteVarsFileAtPath(VarsPath(repoRoot), file) diff --git a/cmd/orbit/cli/harness/vars_test.go b/cmd/orbit/cli/harness/vars_test.go index 0d84c58..03520c0 100644 --- a/cmd/orbit/cli/harness/vars_test.go +++ b/cmd/orbit/cli/harness/vars_test.go @@ -13,7 +13,7 @@ func TestWriteAndLoadHarnessVarsFileRoundTrip(t *testing.T) { repoRoot := t.TempDir() input := bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "HarnessOS", diff --git a/cmd/orbit/cli/progress_integration_test.go b/cmd/orbit/cli/progress_integration_test.go index 42e3a8e..75c17bf 100644 --- a/cmd/orbit/cli/progress_integration_test.go +++ b/cmd/orbit/cli/progress_integration_test.go @@ -15,7 +15,7 @@ func TestTemplateSavePlainProgressPreservesJSONStdout(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/orbit/cli/template/agent_addons_install_test.go b/cmd/orbit/cli/template/agent_addons_install_test.go index 3aa94cb..2e2fe17 100644 --- a/cmd/orbit/cli/template/agent_addons_install_test.go +++ b/cmd/orbit/cli/template/agent_addons_install_test.go @@ -39,7 +39,7 @@ func TestApplyLocalTemplateSnapshotsAgentAddonsWithoutNativeActivation(t *testin bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) diff --git a/cmd/orbit/cli/template/apply.go b/cmd/orbit/cli/template/apply.go index 275026c..31b84f6 100644 --- a/cmd/orbit/cli/template/apply.go +++ b/cmd/orbit/cli/template/apply.go @@ -784,7 +784,7 @@ func applyTemplatePreview(repoRoot string, preview TemplateApplyPreview, overwri func loadOptionalBindingsFile(filename string) (bindings.VarsFile, error) { if strings.TrimSpace(filename) == "" { return bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, }, nil } @@ -805,7 +805,7 @@ func loadOptionalBindingsFile(filename string) (bindings.VarsFile, error) { func loadOptionalRepoVarsFile(ctx context.Context, repoRoot string) (bindings.VarsFile, bool, error) { empty := bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{}, } if _, err := os.Stat(runtimeVarsPath(repoRoot)); err == nil { @@ -910,7 +910,7 @@ func planResolvedBindingsWrite( } planned := bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: merged, } if len(scopedMerged) > 0 { diff --git a/cmd/orbit/cli/template/apply_test.go b/cmd/orbit/cli/template/apply_test.go index babad9c..7fba87a 100644 --- a/cmd/orbit/cli/template/apply_test.go +++ b/cmd/orbit/cli/template/apply_test.go @@ -476,7 +476,7 @@ func TestBuildTemplateApplyPreviewReusesRepoVarsAndCollectsWrites(t *testing.T) repo, sourceRef := seedLocalTemplateApplyRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Local Orbit\n"+ @@ -569,7 +569,7 @@ func TestBuildTemplateApplyPreviewPrefersScopedRepoVars(t *testing.T) { repo, sourceRef := seedLocalTemplateApplyRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Global Orbit\n"+ @@ -608,7 +608,7 @@ func TestBuildTemplateApplyPreviewWritesNamespacedBindingWhenRequested(t *testin repo, sourceRef := seedLocalTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Docs Orbit\n"+ @@ -638,7 +638,7 @@ func TestBuildTemplateApplyPreviewConflictsWhenBindingsWouldRewriteRepoVars(t *t repo, sourceRef := seedLocalTemplateApplyRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Old Orbit\n"+ @@ -646,7 +646,7 @@ func TestBuildTemplateApplyPreviewConflictsWhenBindingsWouldRewriteRepoVars(t *t bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: New Orbit\n"), 0o600)) @@ -674,7 +674,7 @@ func TestBuildTemplateApplyPreviewNamespacesIncompatibleInstallRecordVariableDec repo, sourceRef := seedLocalTemplateApplyRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Existing Orbit\n"+ @@ -726,7 +726,7 @@ func TestBuildTemplateApplyPreviewRendersSharedAgentsPayload(t *testing.T) { repo, sourceRef := seedLocalTemplateApplyRepoWithSharedAgents(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Local Orbit\n"+ @@ -753,7 +753,7 @@ func TestBuildTemplateApplyPreviewWarnsWhenRuntimeAgentsAlreadyHasCurrentOrbitBl repo, sourceRef := seedLocalTemplateApplyRepoWithSharedAgents(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Local Orbit\n") @@ -781,7 +781,7 @@ func TestBuildTemplateApplyPreviewFailsWhenRuntimeAgentsIsMalformed(t *testing.T repo, sourceRef := seedLocalTemplateApplyRepoWithSharedAgents(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Local Orbit\n") @@ -804,7 +804,7 @@ func TestBuildTemplateApplyPreviewReusesUncommittedWorktreeVars(t *testing.T) { repo, sourceRef := seedLocalTemplateApplyRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Worktree Orbit\n"+ @@ -876,7 +876,7 @@ func TestBuildTemplateApplyPreviewUsesEditorBindingsForMissingVariables(t *testi EditorMode: true, Editor: editorFunc(func(_ context.Context, filename string) error { return os.WriteFile(filename, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Edited Orbit\n"+ @@ -905,7 +905,7 @@ func TestBuildTemplateApplyPreviewEditorDoesNotOverrideExistingBindings(t *testi repo, sourceRef := seedLocalTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: From File\n"+ @@ -920,7 +920,7 @@ func TestBuildTemplateApplyPreviewEditorDoesNotOverrideExistingBindings(t *testi Editor: editorFunc(func(_ context.Context, filename string) error { editorCalled = true return os.WriteFile(filename, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: From Editor\n"), 0o600) @@ -962,7 +962,7 @@ func TestBuildTemplateApplyPreviewFailsWhenEditorLeavesRequiredValueEmpty(t *tes EditorMode: true, Editor: editorFunc(func(_ context.Context, filename string) error { return os.WriteFile(filename, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: \"\"\n"+ @@ -979,7 +979,7 @@ func TestBuildTemplateApplyPreviewDoesNotPromptWhenRepoVarsAlreadyResolveBinding repo, sourceRef := seedLocalTemplateApplyRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Local Orbit\n"+ @@ -1007,7 +1007,7 @@ func TestBuildTemplateApplyPreviewDoesNotPromptWhenBindingsFileAlreadyResolveBin repo, sourceRef := seedLocalTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: File Orbit\n"+ @@ -1035,7 +1035,7 @@ func TestApplyLocalTemplateMergesSharedAgentsBlockInPlace(t *testing.T) { repo, sourceRef := seedLocalTemplateApplyRepoWithSharedAgents(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n") @@ -1134,7 +1134,7 @@ func TestApplyLocalTemplateWritesRuntimeFilesDefinitionInstallRecordAndVars(t *t repo, sourceRef := seedLocalTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"+ @@ -1181,7 +1181,7 @@ func TestApplyLocalTemplateRequiresOverwriteForConflictingPaths(t *testing.T) { bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -1231,7 +1231,7 @@ func TestBuildTemplateApplyPreviewPreservesConflictSummaryWhenOverwriteExisting( bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -1258,7 +1258,7 @@ func TestBuildRemoteTemplateApplyPreviewUsesRemoteInstallMetadata(t *testing.T) runtimeRepo := seedRemoteApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Remote Orbit\n"+ @@ -1315,7 +1315,7 @@ func TestApplyRemoteTemplateWritesRuntimeFilesDefinitionInstallRecordAndVars(t * runtimeRepo := seedRemoteApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Remote Orbit\n"+ @@ -1354,7 +1354,7 @@ func TestReplayInstalledTemplateUsesRecordedTemplateCommitInsteadOfCurrentBranch repo, sourceRef := seedLocalTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -1401,7 +1401,7 @@ func TestReplayInstalledRemoteTemplateUsesRecordedTemplateCommitAfterRemoteForce runtimeRepo := seedRemoteApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Remote Orbit\n"), 0o600)) @@ -1473,7 +1473,7 @@ func TestReplayInstalledRemoteTemplateFetchesRecordedCommitPin(t *testing.T) { runtimeRepo := seedRemoteApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Remote Orbit\n"), 0o600)) @@ -1516,7 +1516,7 @@ func TestReplayInstalledRemoteTemplateFallsBackToRecordedRefWhenCommitFetchFails runtimeRepo := seedRemoteApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Remote Orbit\n"), 0o600)) @@ -1567,7 +1567,7 @@ func TestBuildInstallOwnedCleanupPlanFailsClosedWithoutVariablesSnapshot(t *test repo, sourceRef := seedLocalTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -1716,7 +1716,7 @@ func TestAnalyzeInstalledTemplateDriftReportsDefinitionAndRuntimeFileDrift(t *te repo, sourceRef := seedLocalTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -1756,7 +1756,7 @@ func TestAnalyzeInstalledTemplateDriftReportsProvenanceUnresolvable(t *testing.T repo, sourceRef := seedLocalTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -1846,7 +1846,7 @@ func seedLocalTemplateApplyRepo(t *testing.T) (*testutil.Repo, string) { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/orbit/cli/template/bindings_init_test.go b/cmd/orbit/cli/template/bindings_init_test.go index 3b5e541..16d4a53 100644 --- a/cmd/orbit/cli/template/bindings_init_test.go +++ b/cmd/orbit/cli/template/bindings_init_test.go @@ -29,7 +29,7 @@ func TestBuildLocalBindingsInitPreviewReturnsManifestBackedSkeleton(t *testing.T }, preview.Source) require.Equal(t, "docs", preview.Manifest.Template.OrbitID) require.Equal(t, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "", @@ -60,7 +60,7 @@ func TestBuildRemoteBindingsInitPreviewReturnsRemoteSkeleton(t *testing.T) { TemplateCommit: strings.TrimSpace(sourceRepo.Run(t, "rev-parse", sourceRef)), }, preview.Source) require.Equal(t, bindings.VarsFile{ - SchemaVersion: 1, + SchemaVersion: bindings.VarsSchemaVersion, Variables: map[string]bindings.VariableBinding{ "project_name": { Value: "", diff --git a/cmd/orbit/cli/template/bootstrap_planner_test.go b/cmd/orbit/cli/template/bootstrap_planner_test.go index 5025a97..e97078d 100644 --- a/cmd/orbit/cli/template/bootstrap_planner_test.go +++ b/cmd/orbit/cli/template/bootstrap_planner_test.go @@ -239,7 +239,7 @@ func seedBootstrapPlannerRepo(t *testing.T) *testutil.Repo { " updated_at: 2026-04-19T00:00:00Z\n"+ "members: []\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") diff --git a/cmd/orbit/cli/template/brief_backfill_test.go b/cmd/orbit/cli/template/brief_backfill_test.go index ebd1ac2..6eb0aad 100644 --- a/cmd/orbit/cli/template/brief_backfill_test.go +++ b/cmd/orbit/cli/template/brief_backfill_test.go @@ -85,7 +85,7 @@ func TestBackfillOrbitBriefPreservesHostedDefinitionComments(t *testing.T) { " orbit_id: docs\n"+ " source_branch: main\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") @@ -138,7 +138,7 @@ func TestBackfillOrbitBriefReturnsSkippedWhenHostedTemplateAlreadyMatches(t *tes " orbit_id: docs\n"+ " source_branch: main\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") @@ -187,7 +187,7 @@ func TestBackfillOrbitBriefSkipsFormatterPaddingAroundMarkers(t *testing.T) { " orbit_id: docs\n"+ " source_branch: main\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") diff --git a/cmd/orbit/cli/template/content_builder_test.go b/cmd/orbit/cli/template/content_builder_test.go index 2c2c918..156b96e 100644 --- a/cmd/orbit/cli/template/content_builder_test.go +++ b/cmd/orbit/cli/template/content_builder_test.go @@ -19,7 +19,7 @@ func TestBuildTemplateContentFiltersForbiddenPathsAndAddsCompanionDefinition(t * repo := testutil.NewRepo(t) repo.WriteFile(t, ".orbit/config.yaml", "version: 1\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") diff --git a/cmd/orbit/cli/template/publish_test.go b/cmd/orbit/cli/template/publish_test.go index 9153fa7..affa4bb 100644 --- a/cmd/orbit/cli/template/publish_test.go +++ b/cmd/orbit/cli/template/publish_test.go @@ -116,7 +116,7 @@ func TestEnsureBriefExportSyncRejectsDriftedOrbitTemplateBriefUsingPlaceholderCo " include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") @@ -164,7 +164,7 @@ func TestEnsureBriefExportSyncTreatsFormatterMarkerPaddingAsInSync(t *testing.T) " include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") diff --git a/cmd/orbit/cli/template/remote_transport_test.go b/cmd/orbit/cli/template/remote_transport_test.go index 973cf21..fe8498f 100644 --- a/cmd/orbit/cli/template/remote_transport_test.go +++ b/cmd/orbit/cli/template/remote_transport_test.go @@ -20,7 +20,7 @@ func TestBuildRemoteTemplateApplyPreviewExplicitRefUsesSingleFetchFastPath(t *te runtimeRepo := seedRemoteApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Remote Orbit\n"), 0o600)) diff --git a/cmd/orbit/cli/template/save_test.go b/cmd/orbit/cli/template/save_test.go index 5746d30..9fc72a9 100644 --- a/cmd/orbit/cli/template/save_test.go +++ b/cmd/orbit/cli/template/save_test.go @@ -34,7 +34,7 @@ func TestBuildTemplateSavePreviewBuildsManifestAndTemplateTree(t *testing.T) { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -119,7 +119,7 @@ func TestBuildTemplateSavePreviewCollectsAmbiguities(t *testing.T) { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " product_name:\n"+ " value: Orbit\n"+ @@ -167,7 +167,7 @@ func TestBuildTemplateSavePreviewIgnoresNonMarkdownVariableSyntax(t *testing.T) " - docs/**\n"+ " - schema/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -237,7 +237,7 @@ func TestBuildTemplateSavePreviewKeepsAgentsTemplateInCompanionSpecAndSkipsRootA " include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -338,7 +338,7 @@ func TestBuildTemplateSavePreviewSkipsRuntimeGuidanceExportsAndWarns(t *testing. " include_orbit_description: true\n"+ " materialize_agents_from_meta: true\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -410,7 +410,7 @@ func TestBuildTemplateSavePreviewIncludesCapabilityAssetsAndKeepsCapabilitiesInC " include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -484,7 +484,7 @@ func TestBuildTemplateSavePreviewRejectsHostedCapabilitySkillRootMissingSkillMD( " include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") repo.WriteFile(t, "docs/guide.md", "Orbit guide\n") repo.WriteFile(t, "orbit/skills/docs-style/checklist.md", "Use Orbit style guide.\n") @@ -518,7 +518,7 @@ func TestBuildTemplateSavePreviewSkipsEmptySharedAgentsPayload(t *testing.T) { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -565,7 +565,7 @@ func TestBuildTemplateSavePreviewSkipsProjectionVisibleFilesAndAgents(t *testing "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -614,7 +614,7 @@ func TestBuildTemplateSavePreviewSkipsProjectionVisibleFilesFromManifestVariable "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -650,7 +650,7 @@ func TestSaveTemplateBranchFailsClosedOnAmbiguity(t *testing.T) { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " product_name:\n"+ " value: Orbit\n"+ @@ -693,7 +693,7 @@ func TestSaveTemplateBranchWritesTemplateBranch(t *testing.T) { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -739,7 +739,7 @@ func TestSaveTemplateBranchPreservesExecutableFileMode(t *testing.T) { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") repo.WriteFile(t, "docs/build.sh", "#!/bin/sh\necho orbit\n") require.NoError(t, os.Chmod(filepath.Join(repo.Root, "docs", "build.sh"), 0o755)) @@ -777,7 +777,7 @@ func TestBuildTemplateSavePreviewEditTemplateRegeneratesManifestWithoutMutatingR "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -861,7 +861,7 @@ func TestBuildTemplateSavePreviewEditTemplateAllowsEditingSharedAgentsPayloadWit "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -928,7 +928,7 @@ func TestBuildTemplateSavePreviewEditTemplateFailsWhenDefinitionIsRemoved(t *tes "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") diff --git a/cmd/orbit/cli/template_apply_integration_test.go b/cmd/orbit/cli/template_apply_integration_test.go index ce8afda..0e05655 100644 --- a/cmd/orbit/cli/template_apply_integration_test.go +++ b/cmd/orbit/cli/template_apply_integration_test.go @@ -18,7 +18,7 @@ func TestTemplateApplyLocalBranchWritesRuntimeFilesAndDoesNotEnter(t *testing.T) repo := seedTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"+ @@ -46,7 +46,7 @@ func TestTemplateApplyLocalBranchCreatesSharedAgentsFileWhenAbsent(t *testing.T) repo := seedTemplateApplyRepoWithSharedAgents(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"+ @@ -73,7 +73,7 @@ func TestTemplateApplyLocalBranchFailsOnMalformedRuntimeAgents(t *testing.T) { repo := seedTemplateApplyRepoWithSharedAgents(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -155,7 +155,7 @@ func TestTemplateApplyLocalBranchFailsWithoutOrbitTemplateBranchManifest(t *test bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -174,7 +174,7 @@ func TestTemplateApplyDryRunDoesNotWriteRuntimeFiles(t *testing.T) { repo := seedTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -205,7 +205,7 @@ func TestTemplateApplyDryRunOverwriteExistingStillReportsConflicts(t *testing.T) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -276,7 +276,7 @@ func TestTemplateApplyEditorFillsMissingBindingsWithoutMutatingRuntimeBeforeAppl require.NoError(t, os.WriteFile(editorScript, []byte(""+ "#!/bin/sh\n"+ "cat > \"$1\" <<'EOF'\n"+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Editor Orbit\n"+ @@ -310,7 +310,7 @@ func TestTemplateApplyEditorSupportsQuotedEditorCommandWithSpacedPath(t *testing " exit 19\n"+ "fi\n"+ "cat > \"$3\" <<'EOF'\n"+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Quoted Editor Orbit\n"+ @@ -359,7 +359,7 @@ func TestTemplateApplyRequiresOverwriteForExistingConflicts(t *testing.T) { bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -381,7 +381,7 @@ func TestTemplateApplyRequiresOverwriteForRepoVarsConflicts(t *testing.T) { repo := seedTemplateApplyRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Old Orbit\n"+ @@ -389,7 +389,7 @@ func TestTemplateApplyRequiresOverwriteForRepoVarsConflicts(t *testing.T) { bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -422,7 +422,7 @@ func TestTemplateApplyLocalBranchSupportsJSONResultOutput(t *testing.T) { repo := seedTemplateApplyRepo(t) bindingsPath := filepath.Join(repo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Orbit\n"), 0o600)) @@ -487,7 +487,7 @@ func seedTemplateApplyRepo(t *testing.T) *testutil.Repo { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/orbit/cli/template_apply_remote_integration_test.go b/cmd/orbit/cli/template_apply_remote_integration_test.go index 45a5905..0debf1b 100644 --- a/cmd/orbit/cli/template_apply_remote_integration_test.go +++ b/cmd/orbit/cli/template_apply_remote_integration_test.go @@ -20,7 +20,7 @@ func TestTemplateApplyRemoteGitWritesRuntimeFilesAndDoesNotEnter(t *testing.T) { runtimeRepo := seedRemoteTemplateApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Remote Orbit\n"+ @@ -65,7 +65,7 @@ func TestTemplateApplyRemoteGitReplacesSharedAgentsBlockInPlace(t *testing.T) { bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Applied Remote Orbit\n"), 0o600)) @@ -98,7 +98,7 @@ func TestTemplateApplyRemoteGitUsesEditorForMissingBindings(t *testing.T) { require.NoError(t, os.WriteFile(editorScript, []byte(""+ "#!/bin/sh\n"+ "cat > \"$1\" <<'EOF'\n"+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Remote Editor Orbit\n"+ @@ -129,7 +129,7 @@ func TestTemplateApplyRemoteDryRunSupportsJSONAndDoesNotWriteRuntimeFiles(t *tes runtimeRepo := seedRemoteTemplateApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Dry Remote Orbit\n"), 0o600)) @@ -172,7 +172,7 @@ func TestTemplateApplyRemoteDryRunOverwriteExistingKeepsConflictSummaryInJSON(t bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Dry Remote Orbit\n"), 0o600)) @@ -225,7 +225,7 @@ func TestTemplateApplyRemoteAutoSelectsUniqueDefaultTemplate(t *testing.T) { runtimeRepo := seedRemoteTemplateApplyRuntimeRepo(t) bindingsPath := filepath.Join(runtimeRepo.Root, "apply-bindings.yaml") require.NoError(t, os.WriteFile(bindingsPath, []byte(""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Remote Default Orbit\n"), 0o600)) @@ -321,7 +321,7 @@ func seedRemoteTemplateSourceRepo(t *testing.T, specs ...remoteTemplateBranchSpe " commit_append_trailer: true\n"+ " sparse_checkout_mode: no-cone\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/orbit/cli/template_backfill_export_integration_test.go b/cmd/orbit/cli/template_backfill_export_integration_test.go index c1b42b6..0c94dbf 100644 --- a/cmd/orbit/cli/template_backfill_export_integration_test.go +++ b/cmd/orbit/cli/template_backfill_export_integration_test.go @@ -139,7 +139,7 @@ func seedRuntimeRepoWithDriftedBrief(t *testing.T) *testutil.Repo { " updated_at: 2026-04-17T10:00:00Z\n"+ "members: []\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Acme\n") diff --git a/cmd/orbit/cli/template_init_source_integration_test.go b/cmd/orbit/cli/template_init_source_integration_test.go index 66ece22..0490de0 100644 --- a/cmd/orbit/cli/template_init_source_integration_test.go +++ b/cmd/orbit/cli/template_init_source_integration_test.go @@ -212,7 +212,7 @@ func TestTemplateInitSourceFailsWhenHarnessMetadataExists(t *testing.T) { repo := seedTemplateAuthoringRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") diff --git a/cmd/orbit/cli/template_publish_integration_test.go b/cmd/orbit/cli/template_publish_integration_test.go index 7bc89e3..fe6df9f 100644 --- a/cmd/orbit/cli/template_publish_integration_test.go +++ b/cmd/orbit/cli/template_publish_integration_test.go @@ -803,7 +803,7 @@ func TestTemplatePublishFailsWhenSourceBranchContainsHarnessMetadata(t *testing. repo := seedTemplatePublishRepo(t) repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") diff --git a/cmd/orbit/cli/template_save_bootstrap_integration_test.go b/cmd/orbit/cli/template_save_bootstrap_integration_test.go index d09ee63..7fa93e7 100644 --- a/cmd/orbit/cli/template_save_bootstrap_integration_test.go +++ b/cmd/orbit/cli/template_save_bootstrap_integration_test.go @@ -16,7 +16,7 @@ func TestTemplateSaveDryRunIgnoresCompletedBootstrapMembersAndWarns(t *testing.T t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -81,7 +81,7 @@ func TestTemplateSaveDryRunIncludesCompletedBootstrapMembersWhenExplicitlyReques t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ diff --git a/cmd/orbit/cli/template_save_integration_test.go b/cmd/orbit/cli/template_save_integration_test.go index 0166e2c..38792f9 100644 --- a/cmd/orbit/cli/template_save_integration_test.go +++ b/cmd/orbit/cli/template_save_integration_test.go @@ -23,7 +23,7 @@ func TestTemplateSaveCreatesTemplateBranch(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -63,7 +63,7 @@ func TestTemplateSaveCreatesTemplateBranchWithSharedAgentsPayload(t *testing.T) t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -114,7 +114,7 @@ func TestTemplateSaveSkipsProjectionVisibleFilesAndAgents(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -181,7 +181,7 @@ func TestTemplateSaveDryRunDoesNotWriteBranch(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -243,7 +243,7 @@ func TestTemplateSaveUsesZeroCommitProvenanceWithoutCommittedHead(t *testing.T) t.Parallel() repo := seedUncommittedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -277,7 +277,7 @@ func TestTemplateSaveFailsClosedOnDetachedHeadRuntimeRevision(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -295,7 +295,7 @@ func TestTemplateSaveFailsClosedOnDriftedMemberHints(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -327,7 +327,7 @@ func TestTemplateSaveRejectsUntrackedMemberPayloadReferencedByTruth(t *testing.T t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -360,7 +360,7 @@ func TestTemplateSaveAllowsInSyncMemberHints(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -394,7 +394,7 @@ func TestTemplateSaveDryRunWarnsWhenRuntimeAgentsLacksCurrentOrbitMarker(t *test t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -427,7 +427,7 @@ func TestTemplateSaveDryRunSupportsJSONOutput(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -492,7 +492,7 @@ func TestTemplateSaveDryRunJSONIncludesAmbiguitySummary(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " product_name:\n"+ " value: Orbit\n"+ @@ -524,7 +524,7 @@ func TestTemplateSaveSupportsJSONOutput(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -557,7 +557,7 @@ func TestTemplateSaveDefaultFlagOnlyAffectsManifestMetadata(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -574,7 +574,7 @@ func TestTemplateSaveFailsWhenTargetBranchExistsWithoutOverwrite(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -591,7 +591,7 @@ func TestTemplateSaveDryRunFailsClosedOnAmbiguity(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " product_name:\n"+ " value: Orbit\n"+ @@ -614,7 +614,7 @@ func TestTemplateSaveUsesInstallRecordSourceRefAsDefaultWritebackTarget(t *testi t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -648,7 +648,7 @@ func TestTemplateSaveRequiresExplicitTargetForManualRuntimeMembersEvenWithInstal t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -666,7 +666,7 @@ func TestTemplateSaveRequiresExplicitTargetForBundleInstalledRuntimeMembers(t *t t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -692,7 +692,7 @@ func TestTemplateSaveDryRunUsesInstallRecordSourceRefAsDefaultWritebackTarget(t t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -727,7 +727,7 @@ func TestTemplateSaveReadsHiddenTrackedFilesFromHEAD(t *testing.T) { "include:\n"+ " - docs/**\n") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n") @@ -752,7 +752,7 @@ func TestTemplateSaveReadsHiddenTrackedFilesFromHEAD(t *testing.T) { func TestTemplateSaveEditTemplateWritesEditedTemplateWithoutMutatingRuntimeWorktree(t *testing.T) { repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -786,7 +786,7 @@ func TestTemplateSaveEditTemplateWritesEditedTemplateWithoutMutatingRuntimeWorkt func TestTemplateSaveEditTemplatePreservesExecutableFileMode(t *testing.T) { repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") repo.WriteFile(t, "docs/build.sh", "#!/bin/sh\necho orbit\n") require.NoError(t, os.Chmod(filepath.Join(repo.Root, "docs", "build.sh"), 0o755)) @@ -808,7 +808,7 @@ func TestTemplateSaveEditTemplatePreservesExecutableFileMode(t *testing.T) { func TestTemplateSaveEditTemplateSupportsQuotedEditorCommandWithSpacedPath(t *testing.T) { repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables:\n"+ " project_name:\n"+ " value: Orbit\n"+ @@ -851,7 +851,7 @@ func TestTemplateSaveFailsOnCapabilityOwnedMemberOverlap(t *testing.T) { t.Parallel() repo := seedTemplateSaveRepo(t, ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") repo.WriteFile(t, ".harness/orbits/docs.yaml", ""+ "id: docs\n"+ @@ -1048,7 +1048,7 @@ func seedTemplateSaveOutOfRangeSkillRepo(t *testing.T) *testutil.Repo { " - extras/**\n") writeTestRuntimeManifest(t, repo, "docs") repo.WriteFile(t, ".harness/vars.yaml", ""+ - "schema_version: 1\n"+ + "schema_version: 2\n"+ "variables: {}\n") repo.WriteFile(t, "docs/guide.md", "Orbit guide\n") repo.WriteFile(t, "declared-skills/docs-style/SKILL.md", ""+