diff --git a/.github/workflows/npm-release-ops.yml b/.github/workflows/npm-release-ops.yml index f99824a..c8e55b6 100644 --- a/.github/workflows/npm-release-ops.yml +++ b/.github/workflows/npm-release-ops.yml @@ -1,5 +1,10 @@ name: Release +# Release strategy and pre-actions: +# - docs/release.md +# Release probe and publication verification guidance: +# - docs/real-repo-validation.md + on: push: workflow_dispatch: diff --git a/.rabbit/context.yaml b/.rabbit/context.yaml index 3f9f59e..da34818 100644 --- a/.rabbit/context.yaml +++ b/.rabbit/context.yaml @@ -5,8 +5,8 @@ version: udx.dev/dev.kit/v1 generator: tool: dev.kit repo: https://github.com/udx/dev.kit - version: 0.14.0 - generated_at: 2026-07-05T18:19:05Z + version: 0.20.0 + generated_at: 2026-07-08T15:15:15Z sources: homepage: https://udx.dev/kit repository: https://github.com/udx/dev.kit @@ -27,13 +27,14 @@ refs: - ./changes.md - ./Makefile - ./docs/real-repo-validation.md + - ./docs/release.md - ./src/configs/archetypes.yaml - ./src/configs/audit-rules.yaml - ./src/configs/context-config.yaml - ./src/configs/detection-patterns.yaml - ./src/configs/detection-signals.yaml - ./src/configs/repo-validation.yaml - - ./deploy.yml + - ./env-interface.yaml - ./.github/workflows - ./docs @@ -60,13 +61,6 @@ dependencies: used_by: - .github/workflows/context7-ops.yml - .github/workflows/npm-release-ops.yml - - repo: udx/worker - kind: manifest contract (deploy) - resolved: true - declared_as: udx.io/worker-v1/deploy - archetype: manifest-repo - used_by: - - deploy.yml # Manifests — YAML files that define repo-specific workflow, deploy, or contract behavior. # Note: Include custom config/manifests that materially shape repo behavior or contract understanding. @@ -143,28 +137,12 @@ manifests: - path reference: docs/real-repo-validation.md - path reference: lib/modules/config_catalog.sh - path reference: tests/real-repos.sh - - path: deploy.yml - kind: workerDeployConfig - declared_as: udx.io/worker-v1/deploy - source_repo: udx/worker + - path: env-interface.yaml + kind: devKitEnvInterface + description: Environment variables that control dev.kit installation, command behavior, and test probes. + declared_as: udx.dev/dev.kit-v1/config used_by: - - Makefile - - docs/context-contract.md - - docs/references/command-surfaces.md - - docs/references/config-contract-surfaces.md - - docs/repo-contract-boundary.md - - lib/modules/repo_factors.sh - - src/configs/context-config.yaml - - src/configs/detection-signals.yaml - - tests/suite.sh + - changes.md evidence: - - version: udx.io/worker-v1/deploy - - path reference: Makefile - - path reference: docs/context-contract.md - - path reference: docs/references/command-surfaces.md - - path reference: docs/references/config-contract-surfaces.md - - path reference: docs/repo-contract-boundary.md - - path reference: lib/modules/repo_factors.sh - - path reference: src/configs/context-config.yaml - - path reference: src/configs/detection-signals.yaml - - path reference: tests/suite.sh + - version: udx.dev/dev.kit-v1/config + - path reference: changes.md diff --git a/AGENTS.md b/AGENTS.md index ed5733d..dee75a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,7 +24,7 @@ _Normalized repo-owned guidance for agents. Keep it aligned with `docs/reference ## Workflow -- read: `README.md`, `changes.md`, `deploy.yml`, `.github/workflows/`, `docs/` +- read: `README.md`, `changes.md`, `.github/workflows/`, `docs/` - verify: `make test` ## Notes diff --git a/Makefile b/Makefile index d26b307..e9bef19 100644 --- a/Makefile +++ b/Makefile @@ -10,15 +10,14 @@ test: test-real: bash tests/real-repos.sh -# Run tests inside the worker container via deploy.yml -# Requires @udx/worker-deployment: npm install -g @udx/worker-deployment +# Run tests inside the worker container without the deprecated worker-deployment manifest. test-docker: - worker run + docker run --rm -v "$(CURDIR):/workspace" -w /workspace $(WORKER_IMAGE) bash tests/suite.sh # Interactive shell inside the worker container for debugging test-shell: - worker run run-it + docker run --rm -it -v "$(CURDIR):/workspace" -w /workspace $(WORKER_IMAGE) bash # Pull the worker image explicitly test-docker-pull: - docker pull $(WORKER_IMAGE) \ No newline at end of file + docker pull $(WORKER_IMAGE) diff --git a/README.md b/README.md index f9736b6..73ff837 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ All commands support `--json`. - [Environment Config](docs/environment-config.md) - [Context Coverage](docs/context-coverage.md) - [Integration](docs/integration.md) +- [Release](docs/release.md) - [Real Repo Validation](docs/real-repo-validation.md) - [Smart Dependency Detection](docs/smart-dependency-detection.md) - [Reference Docs](docs/references/README.md) diff --git a/changes.md b/changes.md index 679028d..4043d1e 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,12 @@ # Changes +### 0.20.0 + +- Discover root YAML config contracts from explicit top-level `contract` / `contracts` metadata or typed `kind` + `version` manifests instead of filename-specific allowlists. +- Remove the deprecated worker-deployment `deploy.yml` surface and keep manifest discovery/dependency tracing covered by arbitrary typed root YAML such as `work-conf.yaml`. +- Add an explicit `env-interface.yaml` for dev.kit's own environment contract so config coverage comes from a repo-owned interface declaration. +- Document release strategy and pre-actions so PRs check the published version first, reserve the next version, update `changes.md`, regenerate context, and validate before merge. + ### 0.14.0 - Ignore command examples from `docs/references/` when generating repo command contracts, preventing reference docs from creating misleading `build` or `run` commands. diff --git a/deploy.yml b/deploy.yml deleted file mode 100644 index 61993c3..0000000 --- a/deploy.yml +++ /dev/null @@ -1,13 +0,0 @@ -kind: workerDeployConfig -version: udx.io/worker-v1/deploy - -config: - image: "usabilitydynamics/udx-worker:latest" - name: "dev-kit-test-suite" - volumes: - - ".:/workspace" - env: - TERM: "xterm-256color" - command: "/bin/bash" - args: - - "/workspace/tests/suite.sh" diff --git a/docs/context-contract.md b/docs/context-contract.md index 75950c8..2ebb38e 100644 --- a/docs/context-contract.md +++ b/docs/context-contract.md @@ -12,7 +12,7 @@ The generated contract is `.rabbit/context.yaml`. - `AGENTS.md`, `CLAUDE.md`, and similar repo-owned instruction files - `README.md`, `changes.md`, and focused docs - `.github/workflows/` -- manifests such as `deploy.yml`, package manifests, Docker files, and structured YAML configs +- manifests such as typed YAML configs, package manifests, Docker files, and workflow contracts - scripts, Makefiles, tests, and checked-in examples that define runnable behavior Live services such as GitHub issues, PRs, reviews, and workflow runs can help a current task, but they should not become durable repo truth inside `.rabbit/context.yaml`. diff --git a/docs/references/command-surfaces.md b/docs/references/command-surfaces.md index 89c9ec2..4b4f5c2 100644 --- a/docs/references/command-surfaces.md +++ b/docs/references/command-surfaces.md @@ -25,7 +25,7 @@ Workflow and operational contracts are often packaged in: - `.github/workflows/*.yml` when the workflow expresses repo-specific execution contracts - reusable workflow refs - Docker build and runtime files -- deploy manifests such as `deploy.yml` +- typed runtime manifests and workflow files - repo docs that explain how those assets fit together Docs should explain execution behavior, tradeoffs, and decision points. The runnable contract should stay in scripts and manifests. @@ -80,7 +80,7 @@ A repo may expose its main flow through a mix like: - `Makefile` for `make test`, `make build`, `make run` - `.github/workflows/` for CI/CD execution -- `deploy.yml` for deploy contract details +- typed runtime manifests or workflow files for deploy contract details - `docs/` for operator-facing explanation That is valid as long as the repo makes those surfaces clear and traceable. diff --git a/docs/references/config-contract-surfaces.md b/docs/references/config-contract-surfaces.md index 526d79c..94b60a5 100644 --- a/docs/references/config-contract-surfaces.md +++ b/docs/references/config-contract-surfaces.md @@ -10,7 +10,7 @@ Configuration is often declared through: - `.env.example`, `.env.sample`, or `.env.template` - focused repo docs such as `README.md` or `docs/config.md` -- deploy manifests such as `deploy.yml` +- typed YAML manifests with explicit config metadata - versioned YAML/JSON manifests with explicit config metadata or runtime config sections - checked-in example config files when the repo uses a custom format diff --git a/docs/release.md b/docs/release.md new file mode 100644 index 0000000..e840bc1 --- /dev/null +++ b/docs/release.md @@ -0,0 +1,35 @@ +# Release + +This repo releases `@udx/dev-kit` through the release workflow on the release +branch. Release-bound PRs should make the intended package version, changelog, +generated context, and validation evidence explicit before merge. + +## Pre-Actions + +Before opening or updating a release-bound PR: + +- Check the currently published version through GitHub releases and npm. +- If the current `package.json` version is already published, bump to the next + intended version in `package.json` and `package-lock.json`. +- Add pending user-facing changes under that new version in `changes.md`; keep + already published versions as historical records. +- Run `dev.kit repo` after repo contract or release metadata changes so + `.rabbit/context.yaml` records the current generator version. +- Run the focused fixture check first, then `make test`, before asking for + review or merge. + +## Strategy + +- Treat `changes.md` as the release intent. Published versions are immutable + history; new work goes under the next intended version. +- Use the next minor version for ordinary `0.x` feature releases. A `0.x` + minor may change generated context or detection behavior. +- Reserve milestone jumps, such as `0.20.0`, for intentional contract shifts: + removing deprecated surfaces, changing manifest/interface strategy, or + making output changes that users should notice before upgrading. +- Keep release mechanics in GitHub Actions and package metadata, not in + generated context. +- Use `docs/real-repo-validation.md` for optional local probe strategy and + post-release verification evidence. +- Verify GitHub release evidence and npm registry evidence separately before + reporting a release as published. diff --git a/docs/repo-contract-boundary.md b/docs/repo-contract-boundary.md index 70db651..ab2bf67 100644 --- a/docs/repo-contract-boundary.md +++ b/docs/repo-contract-boundary.md @@ -17,7 +17,7 @@ Use **scripts and manifests** for programmatic execution: - `Makefile`, `package.json`, and shell scripts - `.github/workflows/*.yml` -- deploy manifests such as `deploy.yml` +- typed YAML manifests and workflow contracts - checked-in config examples when they are part of the runnable contract Use **structured refs** for deterministic parsing: diff --git a/docs/smart-dependency-detection.md b/docs/smart-dependency-detection.md index 2a74881..865cc5f 100644 --- a/docs/smart-dependency-detection.md +++ b/docs/smart-dependency-detection.md @@ -29,7 +29,7 @@ If `dev.kit` can resolve a dependency confidently, it records: Example: ```yaml -version: udx.io/worker-v1/deploy +version: example.dev/runtime-v1/config ``` That kind of versioned manifest header can be normalized into a dependency repo contract when the repo evidence is strong enough. diff --git a/env-interface.yaml b/env-interface.yaml new file mode 100644 index 0000000..a3d7895 --- /dev/null +++ b/env-interface.yaml @@ -0,0 +1,34 @@ +--- +# dev.kit CLI environment interface. +# References: +# - docs/environment-config.md +# - bin/scripts/install.sh +# - lib/modules/local_env.sh +kind: devKitEnvInterface +version: udx.dev/dev.kit-v1/config +description: Environment variables that control dev.kit installation, command behavior, and test probes. + +config: + env: + DEV_KIT_HOME: + description: dev.kit home directory for curl-managed installs and local config. + required: false + DEV_KIT_BIN_DIR: + description: Directory where dev.kit command shims are installed. + required: false + DEV_KIT_INSTALL_REPO: + description: GitHub repository used by the curl installer. + required: false + DEV_KIT_INSTALL_REF: + description: Branch or ref used by the curl installer. + required: false + DEV_KIT_REPO_SOFT_TIMEOUT: + description: Seconds before repo generation reports a slow-operation notice. + required: false + DEV_KIT_REPO_HARD_TIMEOUT: + description: Seconds before repo generation stops a guarded operation. + required: false + DEV_KIT_SPINNER_DISABLE: + description: Disable spinner output for tests and non-interactive runs. + required: false + secrets: {} diff --git a/lib/modules/local_env.sh b/lib/modules/local_env.sh index dd2c881..6cb7ce7 100644 --- a/lib/modules/local_env.sh +++ b/lib/modules/local_env.sh @@ -198,7 +198,7 @@ dev_kit_env_tool_state() { # Compute tool detection lines. Recomputed on each run. _dev_kit_env_compute_tool_lines() { local tool="" - for tool in git gh npm docker yq jq aws gcloud az "@udx/worker-deployment" "@udx/mcurl"; do + for tool in git gh npm docker yq jq aws gcloud az "@udx/mcurl"; do printf '%s|%s|%s\n' "$tool" "$(dev_kit_env_tool_category "$tool")" "$(dev_kit_env_tool_state "$tool")" done } @@ -241,7 +241,7 @@ dev_kit_env_tool_presence_state() { _dev_kit_env_compute_tool_presence_lines() { local tool="" - for tool in git gh npm docker yq jq aws gcloud az "@udx/worker-deployment" "@udx/mcurl"; do + for tool in git gh npm docker yq jq aws gcloud az "@udx/mcurl"; do printf '%s|%s|%s\n' "$tool" "$(dev_kit_env_tool_category "$tool")" "$(dev_kit_env_tool_presence_state "$tool")" done } @@ -327,7 +327,6 @@ dev_kit_env_tool_enables() { aws) printf 'AWS cloud operations' ;; gcloud) printf 'Google Cloud operations' ;; az) printf 'Azure cloud operations' ;; - "@udx/worker-deployment") printf 'UDX deployment workflows' ;; "@udx/mcurl") printf 'web fetches for agents' ;; *) printf 'general tooling' ;; esac diff --git a/lib/modules/repo_factors.sh b/lib/modules/repo_factors.sh index 098b486..0b642d7 100644 --- a/lib/modules/repo_factors.sh +++ b/lib/modules/repo_factors.sh @@ -662,7 +662,7 @@ dev_kit_repo_factor_repair_target() { printf '%s' "$first_workflow" return 0 fi - printf '%s' "deploy.yml or .github/workflows/" + printf '%s' ".github/workflows/ or dependency manifest" return 0 ;; dependencies:missing) @@ -671,7 +671,7 @@ dev_kit_repo_factor_repair_target() { printf '%s' "$first_workflow" return 0 fi - printf '%s' "deploy.yml or .github/workflows/" + printf '%s' ".github/workflows/ or dependency manifest" return 0 ;; config:partial) @@ -775,11 +775,6 @@ dev_kit_repo_dependency_reference_local() { return 0 fi - if dev_kit_has_file "$repo_dir" "deploy.yml"; then - printf '%s' "deploy.yml" - return 0 - fi - dev_kit_repo_reference_doc_default "$repo_dir" } @@ -825,11 +820,6 @@ dev_kit_repo_pipeline_reference_local() { return 0 fi - if dev_kit_has_file "$repo_dir" "deploy.yml"; then - printf '%s' "deploy.yml" - return 0 - fi - dev_kit_repo_reference_doc_default "$repo_dir" } diff --git a/lib/modules/repo_scaffold.sh b/lib/modules/repo_scaffold.sh index 0bc6653..0da8c25 100644 --- a/lib/modules/repo_scaffold.sh +++ b/lib/modules/repo_scaffold.sh @@ -262,6 +262,58 @@ $(dev_kit_detection_list "workflow_globs" | sed 's#/[^/]*$##' | awk '!seen[$0]++ EOF } +dev_kit_manifest_declares_contract_surface() { + local manifest_path="$1" + + [ -f "$manifest_path" ] || return 1 + + awk ' + /^[[:space:]]*#/ { next } + /^contracts:[[:space:]]*($|#|[^[:space:]])/ { found = 1; exit } + /^contract:[[:space:]]*($|#|[^[:space:]])/ { found = 1; exit } + /^kind:[[:space:]]*[^[:space:]#]/ { has_kind = 1; next } + /^version:[[:space:]]*[^[:space:]#]/ { has_version = 1; next } + END { exit((found || (has_kind && has_version)) ? 0 : 1) } + ' "$manifest_path" +} + +dev_kit_repo_has_configured_root_contract_manifest_file() { + local manifest_rel="$1" + local configured_rel="" + + while IFS= read -r configured_rel; do + [ -n "$configured_rel" ] || continue + [ "$configured_rel" = "$manifest_rel" ] && return 0 + done </dev/null | sort) +EOF +} + dev_kit_repo_contract_manifest_files() { local repo_root="$1" local manifest_dir="" @@ -306,6 +358,8 @@ EOF done <> "$_dep_triples_file" - else - printf '%s|manifest contract|%s\n' "$_vf_version" "$_vf_rel" >> "$_dep_triples_file" - fi - fi + printf '%s\n' "${_vf#"${repo_root}/"}" >> "$_manifest_contract_files_file" done </dev/null | sort) EOF @@ -960,6 +1010,22 @@ $(dev_kit_context_section_detection_list_values "manifests" "config_dirs") EOF while IFS= read -r _vf_rel; do + [ -n "$_vf_rel" ] && [ -f "${repo_root}/${_vf_rel}" ] || continue + case "$_vf_rel" in */context.yaml) continue ;; esac + printf '%s\n' "$_vf_rel" >> "$_manifest_contract_files_file" + done <> "$_manifest_contract_files_file" + done <> "$_dep_triples_file" fi fi - done </dev/null 2>&1 + cat > "$repo_dir/README.md" <<'EOF' +# Declared Config Repo + +Runtime variables are declared in `work-conf.yaml`. +EOF + cat > "$repo_dir/work-conf.yaml" <<'EOF' +--- +# Runtime config contract for the local automation surface. +# References: +# - https://github.com/example/runtime/blob/main/docs/config.md +kind: customRuntimeConfig +version: example.dev/runtime-v1/config +config: + env: {} + secrets: {} +EOF + cat > "$repo_dir/interface-contract.yaml" <<'EOF' +--- +# Explicit contract marker without typed version metadata. +contract: + purpose: local automation interface notes +refs: + - README.md +EOF + cat > "$repo_dir/source-notes.yaml" <<'EOF' +# Source notes with references are useful context, but not a manifest contract. +sources: + - https://github.com/example/runtime/blob/main/docs/config.md +refs: + - README.md +EOF +} + while [ "$#" -gt 0 ]; do case "$1" in --only) @@ -173,16 +216,25 @@ if should_run_explicit "repo-contract"; then docker_repo_json="$(cd "$DOCKER_ACTION_REPO" && dev.kit repo --json)" assert_contains "$docker_repo_json" "\"context\":" "repo contract: docker repo reports context path" - assert_contains "$(json_factor_status "$docker_repo_json" config)" "present" "repo contract: reports present config factor" - assert_contains "$docker_repo_json" "config contract manifest: deploy.yml" "repo contract: manifest config shape satisfies config contract" docker_context_yaml="${DOCKER_ACTION_REPO}/.rabbit/context.yaml" - assert_contains "$(cat "$docker_context_yaml")" "path: deploy.yml" "repo contract: includes deploy manifest" - assert_contains "$(cat "$docker_context_yaml")" "path: .rabbit/deploy.yml" "repo contract: includes hidden custom manifest" assert_contains "$(cat "$docker_context_yaml")" "path: .rabbit/infra_configs/staging/k8s-configmap.yaml" "repo contract: inventories nested rabbit manifests" docker_context_refs="$(awk '/^refs:/{flag=1;next} /^# Commands/{if(flag) exit} flag{print}' "$docker_context_yaml")" assert_not_contains "$docker_context_refs" ".rabbit/infra_configs/staging/k8s-configmap.yaml" "repo contract: excludes nested rabbit manifests from read-first refs" - assert_contains "$(cat "$docker_context_yaml")" "source_repo: udx/worker" "repo contract: traces manifest owner from version" + + setup_declared_config_repo "$DECLARED_CONFIG_REPO" + declared_config_json="$(cd "$DECLARED_CONFIG_REPO" && dev.kit repo --json)" + assert_contains "$(json_factor_status "$declared_config_json" config)" "present" "repo contract: declared root YAML config contract is present" + assert_contains "$declared_config_json" "config contract manifest: work-conf.yaml" "repo contract: reports declared root YAML config contract" + declared_config_context_yaml="${DECLARED_CONFIG_REPO}/.rabbit/context.yaml" + assert_contains "$(cat "$declared_config_context_yaml")" "path: work-conf.yaml" "repo contract: includes declared root YAML manifest" + assert_contains "$(cat "$declared_config_context_yaml")" "path: interface-contract.yaml" "repo contract: includes contract-marker root YAML manifest" + assert_contains "$(cat "$declared_config_context_yaml")" "kind: customRuntimeConfig" "repo contract: records declared root YAML manifest kind" + assert_contains "$(cat "$declared_config_context_yaml")" "source_repo: example/runtime" "repo contract: traces declared root YAML manifest owner from version" + assert_contains "$(cat "$declared_config_context_yaml")" "github reference: example/runtime" "repo contract: records declared root YAML manifest header refs" + declared_config_dependencies="$(awk '/^dependencies:/{flag=1;next} /^# /{if(flag) exit} flag{print}' "$declared_config_context_yaml")" + assert_contains "$declared_config_dependencies" "repo: example/runtime" "repo contract: traces declared root YAML manifest owner as dependency" + assert_not_contains "$(cat "$declared_config_context_yaml")" "path: source-notes.yaml" "repo contract: does not promote source comments alone to manifest" fi if should_run "core"; then @@ -409,17 +461,12 @@ if should_run "core"; then docker_repo_json="$(cd "$DOCKER_ACTION_REPO" && dev.kit repo --json)" assert_contains "$docker_repo_json" "\"context\":" "docker repo: reports context path" - assert_contains "$(json_factor_status "$docker_repo_json" config)" "present" "docker repo: reports present config factor" - assert_contains "$docker_repo_json" "config contract manifest: deploy.yml" "docker repo: manifest config shape satisfies config contract" docker_context_yaml="${DOCKER_ACTION_REPO}/.rabbit/context.yaml" assert_contains "$(cat "$docker_context_yaml")" "generator:" "docker repo: includes generator metadata" - assert_contains "$(cat "$docker_context_yaml")" "path: deploy.yml" "docker repo: includes deploy manifest" - assert_contains "$(cat "$docker_context_yaml")" "path: .rabbit/deploy.yml" "docker repo: includes hidden custom manifest" assert_contains "$(cat "$docker_context_yaml")" "path: .rabbit/infra_configs/staging/k8s-configmap.yaml" "docker repo: inventories nested rabbit manifests" docker_context_refs="$(awk '/^refs:/{flag=1;next} /^# Commands/{if(flag) exit} flag{print}' "$docker_context_yaml")" assert_not_contains "$docker_context_refs" ".rabbit/infra_configs/staging/k8s-configmap.yaml" "docker repo: excludes nested rabbit manifests from read-first refs" - assert_contains "$(cat "$docker_context_yaml")" "source_repo: udx/worker" "docker repo: traces manifest owner from version" mkdir -p "$IGNORED_ACTION_REPO/.next/cache" git -C "$IGNORED_ACTION_REPO" init >/dev/null 2>&1 @@ -429,22 +476,35 @@ EOF cat > "$IGNORED_ACTION_REPO/.gitignore" <<'EOF' .next/ EOF - cat > "$IGNORED_ACTION_REPO/deploy.yml" <<'EOF' -version: udx.io/worker-v1/deploy -kind: workerDeployConfig + cat > "$IGNORED_ACTION_REPO/runtime.yaml" <<'EOF' +version: example.dev/runtime-v1/config +kind: runtimeConfig metadata: env: staging EOF cat > "$IGNORED_ACTION_REPO/.next/cache/reference.txt" <<'EOF' -deploy.yml +runtime.yaml EOF ignored_repo_json="$(cd "$IGNORED_ACTION_REPO" && dev.kit repo --json)" assert_contains "$ignored_repo_json" "\"context\":" "ignored repo: reports context path" - assert_contains "$ignored_repo_json" "no canonical checked-in config contract is declared yet" "ignored repo: deploy filename alone does not satisfy config contract" ignored_context_yaml="${IGNORED_ACTION_REPO}/.rabbit/context.yaml" assert_not_contains "$(cat "$ignored_context_yaml")" ".next/cache/reference.txt" "ignored repo: excludes gitignored artifact references" + setup_declared_config_repo "$DECLARED_CONFIG_REPO" + declared_config_json="$(cd "$DECLARED_CONFIG_REPO" && dev.kit repo --json)" + assert_contains "$(json_factor_status "$declared_config_json" config)" "present" "declared config repo: explicit config contract satisfies config factor" + assert_contains "$declared_config_json" "config contract manifest: work-conf.yaml" "declared config repo: reports explicit config contract" + declared_config_context_yaml="${DECLARED_CONFIG_REPO}/.rabbit/context.yaml" + assert_contains "$(cat "$declared_config_context_yaml")" "path: work-conf.yaml" "declared config repo: includes explicit root YAML manifest" + assert_contains "$(cat "$declared_config_context_yaml")" "path: interface-contract.yaml" "declared config repo: includes contract-marker root YAML manifest" + assert_contains "$(cat "$declared_config_context_yaml")" "kind: customRuntimeConfig" "declared config repo: records explicit root YAML manifest kind" + assert_contains "$(cat "$declared_config_context_yaml")" "source_repo: example/runtime" "declared config repo: traces explicit root YAML manifest owner from version" + assert_contains "$(cat "$declared_config_context_yaml")" "github reference: example/runtime" "declared config repo: records explicit root YAML manifest header refs" + declared_config_dependencies="$(awk '/^dependencies:/{flag=1;next} /^# /{if(flag) exit} flag{print}' "$declared_config_context_yaml")" + assert_contains "$declared_config_dependencies" "repo: example/runtime" "declared config repo: traces explicit root YAML manifest owner as dependency" + assert_not_contains "$(cat "$declared_config_context_yaml")" "path: source-notes.yaml" "declared config repo: does not promote source comments alone to manifest" + mkdir -p "$WORKFLOW_CONTRACT_REPO/.github/workflows" git -C "$WORKFLOW_CONTRACT_REPO" init >/dev/null 2>&1 cat > "$WORKFLOW_CONTRACT_REPO/README.md" <<'EOF'