From 32371469b9a4dc7e02fa4cb8f13a0959a7762100 Mon Sep 17 00:00:00 2001 From: ci Date: Fri, 4 Sep 2026 15:19:29 -0400 Subject: [PATCH 1/5] Assemble inactive default profile --- README.md | 13 +++ RESTORE.md | 15 +++ ci/required-files.txt | 11 ++ .../v1/manifests/claude-code-producer.json | 1 + .../v1/manifests/codex-native-reviewer.json | 1 + .../v1/manifests/deterministic-verifier.json | 1 + .../v1/manifests/dormant-publisher.json | 1 + .../v1/manifests/github-actions-ci.json | 1 + .../default/v1/manifests/github-forge.json | 1 + .../v1/manifests/local-git-materializer.json | 1 + profiles/default/v1/profile.json | 1 + scripts/test/default-profile-assembly.test.sh | 105 ++++++++++++++++++ 12 files changed, 152 insertions(+) create mode 100644 profiles/default/v1/manifests/claude-code-producer.json create mode 100644 profiles/default/v1/manifests/codex-native-reviewer.json create mode 100644 profiles/default/v1/manifests/deterministic-verifier.json create mode 100644 profiles/default/v1/manifests/dormant-publisher.json create mode 100644 profiles/default/v1/manifests/github-actions-ci.json create mode 100644 profiles/default/v1/manifests/github-forge.json create mode 100644 profiles/default/v1/manifests/local-git-materializer.json create mode 100644 profiles/default/v1/profile.json create mode 100755 scripts/test/default-profile-assembly.test.sh diff --git a/README.md b/README.md index 5a7015f..b585467 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,19 @@ The private native snapshot helper is the exception recorded in `work/portable-profile-resolution/spec.md`. Remove it only when every supported runtime has an equivalent accepted descriptor-relative no-follow API. +## Inactive default profile assembly + +`profiles/default/v1/` binds the seven default adapter packages to exact Git +objects from one durable main commit. Protected roles keep distinct principals, +execution boundaries, and authority scopes; their decision records cite the exact +accepted `ROADMAP.md` content. The profile requests no adapter tools, and the CI, +identity, and dormant-publisher roles request no capability or permission. + +This is source data only. It is not selected, resolved, qualified, installed, or +activated, and it cannot invoke a model, use a credential, contact a provider, +publish, or touch a target. Run +`bash scripts/test/default-profile-assembly.test.sh` for the focused proof. + ## Inactive portable core v2 fake-forge contract `core/v2/` contains an inactive, repo-only contract for deterministic candidate diff --git a/RESTORE.md b/RESTORE.md index dce165d..6b04bbe 100644 --- a/RESTORE.md +++ b/RESTORE.md @@ -55,6 +55,21 @@ with the restored `scripts/core-contract.sh`. No compiled helper is installed or restored. A future activation must separately qualify and bind a production trusted parent; restoring these files does not select a live profile. +### Restore the inactive default profile assembly + +Restore the nine paths listed under “Inactive default profile assembly” in +[`ci/required-files.txt`](ci/required-files.txt) from one commit, then run: + +```sh +bash scripts/test/default-profile-assembly.test.sh +``` + +The proof validates the profile and seven manifests, their exact main package +objects, the accepted Roadmap decision record, role separation, and empty tool +grants. Restoring these records does not select, resolve, qualify, install, or +activate the profile and performs no model, credential, provider, publish, or +target operation. + --- ## 1. Recreate yshifu (the manager) diff --git a/ci/required-files.txt b/ci/required-files.txt index c7dac9b..fb86969 100644 --- a/ci/required-files.txt +++ b/ci/required-files.txt @@ -273,3 +273,14 @@ scripts/test/default-dormant-publisher-adapter.test.sh # Inactive deterministic verifier normalizer payload adapters/deterministic-verifier/v1/normalize.jq scripts/test/default-deterministic-verifier-adapter.test.sh + +# Inactive default profile assembly +profiles/default/v1/profile.json +profiles/default/v1/manifests/claude-code-producer.json +profiles/default/v1/manifests/codex-native-reviewer.json +profiles/default/v1/manifests/deterministic-verifier.json +profiles/default/v1/manifests/dormant-publisher.json +profiles/default/v1/manifests/github-actions-ci.json +profiles/default/v1/manifests/github-forge.json +profiles/default/v1/manifests/local-git-materializer.json +scripts/test/default-profile-assembly.test.sh diff --git a/profiles/default/v1/manifests/claude-code-producer.json b/profiles/default/v1/manifests/claude-code-producer.json new file mode 100644 index 0000000..e047f54 --- /dev/null +++ b/profiles/default/v1/manifests/claude-code-producer.json @@ -0,0 +1 @@ +{"body":{"adapter_version":"v1","offered_capabilities":["core.harness.produce.v1"],"offered_execution_kinds":["model"],"offered_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"offered_roles":["producer"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/claude-code-producer/v1/normalize.jq"},"mode":"100644","object_id":"8af4d80e04f6f3877861e55c216a5891830b03b6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.claude-code-producer.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/manifests/codex-native-reviewer.json b/profiles/default/v1/manifests/codex-native-reviewer.json new file mode 100644 index 0000000..dec7d8a --- /dev/null +++ b/profiles/default/v1/manifests/codex-native-reviewer.json @@ -0,0 +1 @@ +{"body":{"adapter_version":"v1","offered_capabilities":["core.review.change.v1"],"offered_execution_kinds":["model"],"offered_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.target.read.v1"],"offered_roles":["reviewer"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/codex-native-reviewer/v1/normalize.jq"},"mode":"100644","object_id":"432f09f36f8c93076388e4a26dba56b6ee7a2bf9","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.codex-native-reviewer.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/manifests/deterministic-verifier.json b/profiles/default/v1/manifests/deterministic-verifier.json new file mode 100644 index 0000000..f472c45 --- /dev/null +++ b/profiles/default/v1/manifests/deterministic-verifier.json @@ -0,0 +1 @@ +{"body":{"adapter_version":"v1","offered_capabilities":["core.verify.run.v1"],"offered_execution_kinds":["deterministic"],"offered_permissions":["core.perm.candidate.execute.v1","core.perm.evidence.write.v1","core.perm.target.read.v1"],"offered_roles":["verifier"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/deterministic-verifier/v1/normalize.jq"},"mode":"100644","object_id":"15fbf4648ee33b8c2fe15ab04357376313f900f6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.deterministic-verifier.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/manifests/dormant-publisher.json b/profiles/default/v1/manifests/dormant-publisher.json new file mode 100644 index 0000000..2845d89 --- /dev/null +++ b/profiles/default/v1/manifests/dormant-publisher.json @@ -0,0 +1 @@ +{"body":{"adapter_version":"v1","offered_capabilities":[],"offered_execution_kinds":["deterministic"],"offered_permissions":[],"offered_roles":["publisher"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/dormant-publisher/v1/normalize.jq"},"mode":"100644","object_id":"86ed0cd6b740a192b829044d7bcb7187e5f38422","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.dormant-publisher.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/manifests/github-actions-ci.json b/profiles/default/v1/manifests/github-actions-ci.json new file mode 100644 index 0000000..b07ee0b --- /dev/null +++ b/profiles/default/v1/manifests/github-actions-ci.json @@ -0,0 +1 @@ +{"body":{"adapter_version":"v1","offered_capabilities":[],"offered_execution_kinds":["deterministic"],"offered_permissions":[],"offered_roles":["ci"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/github-actions-ci/v1/normalize.jq"},"mode":"100644","object_id":"2fad7d2d217a5704fcd4e2d1f559309aa832d16d","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.github-actions-ci.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/manifests/github-forge.json b/profiles/default/v1/manifests/github-forge.json new file mode 100644 index 0000000..74ce169 --- /dev/null +++ b/profiles/default/v1/manifests/github-forge.json @@ -0,0 +1 @@ +{"body":{"adapter_version":"v1","offered_capabilities":[],"offered_execution_kinds":["deterministic"],"offered_permissions":[],"offered_roles":["identity"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/github-forge/v1/normalize.jq"},"mode":"100644","object_id":"feb4622bc4371dce337b1406062919ef2c2c5b49","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.github-forge.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/manifests/local-git-materializer.json b/profiles/default/v1/manifests/local-git-materializer.json new file mode 100644 index 0000000..38c71b5 --- /dev/null +++ b/profiles/default/v1/manifests/local-git-materializer.json @@ -0,0 +1 @@ +{"body":{"adapter_version":"v1","offered_capabilities":["core.forge.materialize-candidate.v2"],"offered_execution_kinds":["deterministic"],"offered_permissions":["core.perm.candidate-repository.write.v2","core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"offered_roles":["forge"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/local-git-materializer/v1"},"mode":"040000","object_id":"277863b98b49e54e2cd826b3f32913fd49c51abf","object_type":"tree","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.local-git-materializer.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/profile.json b/profiles/default/v1/profile.json new file mode 100644 index 0000000..36dc0e4 --- /dev/null +++ b/profiles/default/v1/profile.json @@ -0,0 +1 @@ +{"body":{"bindings":[{"adapter_instance_id":"instance.ci","binding_id":"binding.ci","execution_boundary_id":"boundary.ci","execution_kind":"deterministic","manifest_ref":{"id":"adapter.github-actions-ci.v1","kind":"adapter_manifest","schema_version":2,"sha256":"a5cf4b1b94e32d850e3d056024fa2d2c3977b977fb08323e99b89f8c159baff3"},"package_ref":{"location":{"kind":"path","value":"adapters/github-actions-ci/v1/normalize.jq"},"mode":"100644","object_id":"2fad7d2d217a5704fcd4e2d1f559309aa832d16d","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.ci","requested_capabilities":[],"requested_permissions":[],"requested_tools":[],"role":"ci","skill_refs":[]},{"adapter_instance_id":"instance.forge","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"e31dd669bf048817b503928e51191809cf3a3718d328dc5ab8875a4fe9be2911","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-forge","media_type":"application/json","sha256":"e31dd669bf048817b503928e51191809cf3a3718d328dc5ab8875a4fe9be2911"}}}},"binding_id":"binding.forge","execution_boundary_id":"boundary.forge","execution_kind":"deterministic","manifest_ref":{"id":"adapter.local-git-materializer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"47c5884ca83597a09f1122467c9c0dfd3ea5b4e0256d2d52ae648167349bffe5"},"package_ref":{"location":{"kind":"path","value":"adapters/local-git-materializer/v1"},"mode":"040000","object_id":"277863b98b49e54e2cd826b3f32913fd49c51abf","object_type":"tree","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.forge","requested_capabilities":["core.forge.materialize-candidate.v2"],"requested_permissions":["core.perm.candidate-repository.write.v2","core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"forge","skill_refs":[]},{"adapter_instance_id":"instance.identity","binding_id":"binding.identity","execution_boundary_id":"boundary.identity","execution_kind":"deterministic","manifest_ref":{"id":"adapter.github-forge.v1","kind":"adapter_manifest","schema_version":2,"sha256":"a6290a480ab72b7deac2bc74bc63e35e4fa1dc952bab47de4b17ee9134476044"},"package_ref":{"location":{"kind":"path","value":"adapters/github-forge/v1/normalize.jq"},"mode":"100644","object_id":"feb4622bc4371dce337b1406062919ef2c2c5b49","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.identity","requested_capabilities":[],"requested_permissions":[],"requested_tools":[],"role":"identity","skill_refs":[]},{"adapter_instance_id":"instance.producer","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"b35cdd26196d8d93abe1c387cd4edcf9a130ddcc7a718b2431ddf94135eb19d5","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-producer","media_type":"application/json","sha256":"b35cdd26196d8d93abe1c387cd4edcf9a130ddcc7a718b2431ddf94135eb19d5"}}}},"binding_id":"binding.producer","execution_boundary_id":"boundary.producer","execution_kind":"model","manifest_ref":{"id":"adapter.claude-code-producer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"d849818eb02c96972e1ac90540fd1b00749384f07bb56ed66f0800f78537479e"},"model_request":{"effort_id":"high","model_id":"claude.sonnet","provider_id":"anthropic"},"package_ref":{"location":{"kind":"path","value":"adapters/claude-code-producer/v1/normalize.jq"},"mode":"100644","object_id":"8af4d80e04f6f3877861e55c216a5891830b03b6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.producer","prompt_ref":{"location":{"kind":"path","value":"routines/coder.md"},"mode":"100644","object_id":"b307b85339fbfc060aec59c625918a3f20707438","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"requested_capabilities":["core.harness.produce.v1"],"requested_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"producer","skill_refs":[]},{"adapter_instance_id":"instance.publisher","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"9d00187a85fea0021fac962ee13791a14420fb71f4c9e5dcb23a392d5cf0436e","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-publisher","media_type":"application/json","sha256":"9d00187a85fea0021fac962ee13791a14420fb71f4c9e5dcb23a392d5cf0436e"}}}},"binding_id":"binding.publisher","execution_boundary_id":"boundary.publisher","execution_kind":"deterministic","manifest_ref":{"id":"adapter.dormant-publisher.v1","kind":"adapter_manifest","schema_version":2,"sha256":"e780e0ceb0a305928d6c1fec127cfc6db0140cf2e48b3921e23e59d942419029"},"package_ref":{"location":{"kind":"path","value":"adapters/dormant-publisher/v1/normalize.jq"},"mode":"100644","object_id":"86ed0cd6b740a192b829044d7bcb7187e5f38422","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.publisher","requested_capabilities":[],"requested_permissions":[],"requested_tools":[],"role":"publisher","skill_refs":[]},{"adapter_instance_id":"instance.reviewer","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"a74f15bc7a469e74924725ab9c319ed9162f44fa12b3cf850798f8274c446b6a","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-reviewer","media_type":"application/json","sha256":"a74f15bc7a469e74924725ab9c319ed9162f44fa12b3cf850798f8274c446b6a"}}}},"binding_id":"binding.reviewer","execution_boundary_id":"boundary.reviewer","execution_kind":"model","manifest_ref":{"id":"adapter.codex-native-reviewer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"2f1ceaacd455e6cadc09f2762c6735eab48b91890240b6031af3db744a1175c4"},"model_request":{"effort_id":"high","model_id":"codex.review","provider_id":"openai"},"package_ref":{"location":{"kind":"path","value":"adapters/codex-native-reviewer/v1/normalize.jq"},"mode":"100644","object_id":"432f09f36f8c93076388e4a26dba56b6ee7a2bf9","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.reviewer","prompt_ref":{"location":{"kind":"path","value":"reviewer/codex-review.md"},"mode":"100644","object_id":"b757f78b26f926a6688077a81f5b68a37c1c6690","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"requested_capabilities":["core.review.change.v1"],"requested_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"reviewer","skill_refs":[]},{"adapter_instance_id":"instance.verifier","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"aa7447ee06f5e2a74124f2d0a9d96a4e7552e626ccbd6e60a5ba694331effe04","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-verifier","media_type":"application/json","sha256":"aa7447ee06f5e2a74124f2d0a9d96a4e7552e626ccbd6e60a5ba694331effe04"}}}},"binding_id":"binding.verifier","execution_boundary_id":"boundary.verifier","execution_kind":"deterministic","manifest_ref":{"id":"adapter.deterministic-verifier.v1","kind":"adapter_manifest","schema_version":2,"sha256":"58f65eeac7dc8292e48adf6e1d0e8235d5a19c92521993c74b7b3368bb3f36fe"},"package_ref":{"location":{"kind":"path","value":"adapters/deterministic-verifier/v1/normalize.jq"},"mode":"100644","object_id":"15fbf4648ee33b8c2fe15ab04357376313f900f6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.verifier","requested_capabilities":["core.verify.run.v1"],"requested_permissions":["core.perm.candidate.execute.v1","core.perm.evidence.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"verifier","skill_refs":[]}],"profile_version":"v1"},"id":"profile.default.v1","kind":"profile","schema_version":2} diff --git a/scripts/test/default-profile-assembly.test.sh b/scripts/test/default-profile-assembly.test.sh new file mode 100755 index 0000000..b8c3c85 --- /dev/null +++ b/scripts/test/default-profile-assembly.test.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +set -euo pipefail +export LC_ALL=C + +root=$(CDPATH='' cd -P -- "${BASH_SOURCE[0]%/*}/../.." && pwd -P) +profile="$root/profiles/default/v1/profile.json" +manifest_root="$root/profiles/default/v1/manifests" +manifests=("$manifest_root"/*.json) +roadmap="$root/ROADMAP.md" +roadmap_sha='1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107' +package_commit='a637451d4b3fbef6b516a9c08f68c0dde46a7059' +fail() { printf 'FAIL: %s\n' "$1" >&2; exit 1; } +pass=0 +ok() { pass=$((pass + 1)); printf 'ok %s - %s\n' "$pass" "$1"; } +sha_file() { /usr/bin/shasum -a 256 "$1" | /usr/bin/awk '{print $1}'; } + +[ "$(jq --version)" = jq-1.6 ] || fail jq-version +[ "${#manifests[@]}" -eq 7 ] || fail manifest-count +scripts_core="$root/scripts/core-contract.sh" +"$scripts_core" validate-document "$profile" || fail profile-document +for manifest in "${manifests[@]}"; do + "$scripts_core" validate-document "$manifest" || fail "manifest-${manifest##*/}" +done +ok 'profile and seven manifests pass core v2 document validation' + +jq -e ' + .id == "profile.default.v1" and .body.profile_version == "v1" and + (.body.bindings | length) == 7 and + ([.body.bindings[].role] | sort) == + ["ci","forge","identity","producer","publisher","reviewer","verifier"] and + ([.body.bindings[].binding_id] | unique | length) == 7 and + ([.body.bindings[].adapter_instance_id] | unique | length) == 7 and + ([.body.bindings[].principal_id] | unique | length) == 7 and + ([.body.bindings[].execution_boundary_id] | unique | length) == 7 and + all(.body.bindings[] | select(.role|IN("forge","producer","publisher","reviewer","verifier")); + has("authority_ref")) and + ([.body.bindings[] | select(has("authority_ref"))] | length) == 5 and + all(.body.bindings[] | select(.role|IN("ci","identity")); + has("authority_ref") | not) and + all(.body.bindings[] | select(.role|IN("ci","identity","publisher")); + .requested_capabilities == [] and .requested_permissions == []) +' "$profile" >/dev/null || fail role-graph +ok 'roles and protected boundaries are complete and separated' + +[ "$(sha_file "$roadmap")" = "$roadmap_sha" ] || fail roadmap-digest +jq -e --arg digest "$roadmap_sha" ' + all(.body.bindings[] | select(has("authority_ref")); + .authority_ref.decision_record_ref == { + content_id:"roadmap", + media_type:"text/markdown", + sha256:$digest + }) +' "$profile" >/dev/null || fail authority-decision-record +ok 'protected authority scopes cite the accepted Roadmap decision record' + +for manifest in "${manifests[@]}"; do + digest=$(sha_file "$manifest") + id=$(jq -r .id "$manifest") + jq -e --arg id "$id" --arg digest "$digest" --slurpfile manifest "$manifest" ' + [.body.bindings[] | + select(.manifest_ref.id==$id and .manifest_ref.sha256==$digest)] as $matches | + ($matches | length) == 1 and + ($matches[0] as $binding | $manifest[0].body as $offered | + ($offered.offered_roles | index($binding.role)) != null and + ($offered.offered_execution_kinds | index($binding.execution_kind)) != null and + all($binding.requested_capabilities[]; . as $item | + ($offered.offered_capabilities | index($item)) != null) and + all($binding.requested_permissions[]; . as $item | + ($offered.offered_permissions | index($item)) != null) and + all($binding.requested_tools[]; . as $item | + ($offered.offered_tools | index($item)) != null) and + $binding.package_ref == $offered.package_ref) + ' "$profile" >/dev/null || fail "manifest-graph-$id" + commit=$(jq -r .body.package_ref.revision.commit_id "$manifest") + [ "$commit" = "$package_commit" ] || fail "package-commit-$id" + path=$(jq -r .body.package_ref.location.value "$manifest") + oid=$(jq -r .body.package_ref.object_id "$manifest") + mode=$(jq -r .body.package_ref.mode "$manifest") + type=$(jq -r .body.package_ref.object_type "$manifest") + record=$(git -C "$root" ls-tree "$commit" "$path") + [ "$record" = "$mode $type $oid"$'\t'"$path" ] || fail "package-object-$id" +done +while IFS= read -r ref; do + commit=$(jq -r .revision.commit_id <<<"$ref") + path=$(jq -r .location.value <<<"$ref") + [ "$commit" = "$package_commit" ] || fail "prompt-commit-$path" + oid=$(jq -r .object_id <<<"$ref") + mode=$(jq -r .mode <<<"$ref") + type=$(jq -r .object_type <<<"$ref") + record=$(git -C "$root" ls-tree "$commit" "$path") + [ "$record" = "$mode $type $oid"$'\t'"$path" ] || fail "prompt-object-$path" +done < <(jq -c '.body.bindings[] | .prompt_ref? // empty' "$profile") +ok 'every manifest graph and selected Git object is exact' + +jq -e ' + all(.body.bindings[]; + .requested_tools == [] and .skill_refs == []) and + (.body.bindings[] | select(.role=="producer") | + .model_request.provider_id=="anthropic" and .prompt_ref.location.value=="routines/coder.md") and + (.body.bindings[] | select(.role=="reviewer") | + .model_request.provider_id=="openai" and .prompt_ref.location.value=="reviewer/codex-review.md") +' "$profile" >/dev/null || fail default-selection +ok 'default model preferences are data and no tool is granted' + +printf 'default profile assembly: %s focused checks passed\n' "$pass" From 62e9887c2151315648a2b8c6844fe2742f9b7646 Mon Sep 17 00:00:00 2001 From: ci Date: Fri, 4 Sep 2026 15:55:13 -0400 Subject: [PATCH 2/5] Pin jq for default profile proof --- scripts/test/default-profile-assembly.test.sh | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/scripts/test/default-profile-assembly.test.sh b/scripts/test/default-profile-assembly.test.sh index b8c3c85..3f76e62 100755 --- a/scripts/test/default-profile-assembly.test.sh +++ b/scripts/test/default-profile-assembly.test.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC2016 set -euo pipefail export LC_ALL=C @@ -14,6 +15,58 @@ pass=0 ok() { pass=$((pass + 1)); printf 'ok %s - %s\n' "$pass" "$1"; } sha_file() { /usr/bin/shasum -a 256 "$1" | /usr/bin/awk '{print $1}'; } +tmp=$(/usr/bin/mktemp -d "${TMPDIR:-/tmp}/ystack-default-profile.XXXXXX") +download='' +cleanup() { + if [ -n "$download" ] && [ -f "$download" ]; then + /bin/rm -f -- "$download" + fi + /bin/rm -rf -- "$tmp" +} +trap cleanup EXIT + +platform=$(/usr/bin/uname -s):$(/usr/bin/uname -m) +case "$platform" in + Linux:x86_64) + asset='jq-linux64' + asset_sha='af986793a515d500ab2d35f8d2aecd656e764504b789b66d7e1a0b727a124c44' + ;; + Darwin:x86_64|Darwin:arm64) + asset='jq-osx-amd64' + asset_sha='5c0a0a3ea600f302ee458b30317425dd9632d1ad8882259fcaf4e9b868b2b1ef' + ;; + *) fail "unsupported jq 1.6 proof platform: $platform" ;; +esac + +cache="${TMPDIR:-/tmp}/ystack-portable-core-jq16" +/bin/mkdir -p "$cache" +jq_bin="$cache/$asset" +if [ ! -f "$jq_bin" ] || [ -L "$jq_bin" ] || + [ "$(sha_file "$jq_bin")" != "$asset_sha" ]; then + download=$(/usr/bin/mktemp "$cache/.jq-1.6.XXXXXX") + /usr/bin/curl --proto '=https' --tlsv1.2 -fsSL \ + "https://github.com/jqlang/jq/releases/download/jq-1.6/$asset" \ + -o "$download" + [ "$(sha_file "$download")" = "$asset_sha" ] || fail jq-download-digest + /bin/chmod 0555 "$download" + /bin/mv "$download" "$jq_bin" + download='' +fi + +jq_runtime="$tmp/bin" +/bin/mkdir "$jq_runtime" +if [ "$platform" = Darwin:arm64 ]; then + /bin/ln -s "$jq_bin" "$jq_runtime/jq-real" + /usr/bin/printf '%s\n' '#!/bin/sh' \ + 'exec /usr/bin/arch -x86_64 "${0%/*}/jq-real" "$@"' >"$jq_runtime/jq" + /bin/chmod 0555 "$jq_runtime/jq" +else + /bin/ln -s "$jq_bin" "$jq_runtime/jq" +fi +export PATH="$jq_runtime:$PATH" + +[ ! -L "$jq_bin" ] && [ "$(sha_file "$jq_bin")" = "$asset_sha" ] || + fail jq-cache-digest [ "$(jq --version)" = jq-1.6 ] || fail jq-version [ "${#manifests[@]}" -eq 7 ] || fail manifest-count scripts_core="$root/scripts/core-contract.sh" From 7fc2a040c24de1d184cba6b96d8b9d4922a89c4a Mon Sep 17 00:00:00 2001 From: ci Date: Fri, 4 Sep 2026 16:24:53 -0400 Subject: [PATCH 3/5] Support shallow default profile proof --- scripts/test/default-profile-assembly.test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/test/default-profile-assembly.test.sh b/scripts/test/default-profile-assembly.test.sh index 3f76e62..90984fb 100755 --- a/scripts/test/default-profile-assembly.test.sh +++ b/scripts/test/default-profile-assembly.test.sh @@ -130,7 +130,7 @@ for manifest in "${manifests[@]}"; do oid=$(jq -r .body.package_ref.object_id "$manifest") mode=$(jq -r .body.package_ref.mode "$manifest") type=$(jq -r .body.package_ref.object_type "$manifest") - record=$(git -C "$root" ls-tree "$commit" "$path") + record=$(git -C "$root" ls-tree HEAD "$path") [ "$record" = "$mode $type $oid"$'\t'"$path" ] || fail "package-object-$id" done while IFS= read -r ref; do @@ -140,7 +140,7 @@ while IFS= read -r ref; do oid=$(jq -r .object_id <<<"$ref") mode=$(jq -r .mode <<<"$ref") type=$(jq -r .object_type <<<"$ref") - record=$(git -C "$root" ls-tree "$commit" "$path") + record=$(git -C "$root" ls-tree HEAD "$path") [ "$record" = "$mode $type $oid"$'\t'"$path" ] || fail "prompt-object-$path" done < <(jq -c '.body.bindings[] | .prompt_ref? // empty' "$profile") ok 'every manifest graph and selected Git object is exact' From aa285f3f9b6741077629e247b0b6b9f0817f726e Mon Sep 17 00:00:00 2001 From: ci Date: Fri, 4 Sep 2026 17:24:11 -0400 Subject: [PATCH 4/5] Anchor inactive producer config --- profiles/default/v1/producer-config.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 profiles/default/v1/producer-config.json diff --git a/profiles/default/v1/producer-config.json b/profiles/default/v1/producer-config.json new file mode 100644 index 0000000..369159a --- /dev/null +++ b/profiles/default/v1/producer-config.json @@ -0,0 +1 @@ +{"effort_id":"high","model_id":"claude.sonnet","provider_id":"anthropic","schema_version":1} From 43823f5b39dd6d351050256104582f44654332be Mon Sep 17 00:00:00 2001 From: ci Date: Sat, 5 Sep 2026 12:59:49 -0400 Subject: [PATCH 5/5] Pin the producer config and prove the assembled profile on the real normalizer Completes the in-progress fix for the two review findings on this PR. - P1: the producer manifest carries config_contract_ref and the producer binding carries config_ref, both bound to the immutable profiles/default/v1/producer-config.json blob. The test now builds a resolved profile for the assembled profile and runs the real Claude Code producer normalizer over changed and unchanged snapshots; a missing config is rejected. - P2: every pinned object is resolved at its recorded revision. The test fetches each recorded commit from origin by exact hash into a private history repository and runs ls-tree there, never against HEAD. - The profile now binds six adapters. The identity role, which had been bound to the GitHub forge observation payload, is dropped; that payload is not a forge materializer and remains a separate observation payload. The config reference currently names the pushed commit that introduced the config payload. Once that payload lands on main through its own PR, the reference is re-pinned to the main commit in a follow-up commit here. Co-Authored-By: Claude Fable 5.1 --- README.md | 16 +- RESTORE.md | 10 +- ci/required-files.txt | 2 +- .../v1/manifests/claude-code-producer.json | 2 +- .../default/v1/manifests/github-forge.json | 1 - profiles/default/v1/profile.json | 2 +- scripts/test/default-profile-assembly.test.sh | 245 +++++++++++++++++- 7 files changed, 251 insertions(+), 27 deletions(-) delete mode 100644 profiles/default/v1/manifests/github-forge.json diff --git a/README.md b/README.md index b585467..4dc1e32 100644 --- a/README.md +++ b/README.md @@ -37,15 +37,21 @@ runtime has an equivalent accepted descriptor-relative no-follow API. ## Inactive default profile assembly -`profiles/default/v1/` binds the seven default adapter packages to exact Git +`profiles/default/v1/` binds six default adapter packages to exact Git objects from one durable main commit. Protected roles keep distinct principals, execution boundaries, and authority scopes; their decision records cite the exact -accepted `ROADMAP.md` content. The profile requests no adapter tools, and the CI, -identity, and dormant-publisher roles request no capability or permission. +accepted `ROADMAP.md` content. The producer manifest and binding also pin the +profile's immutable producer config. Requested capabilities and permissions are +inactive contract data, not grants. The profile requests no adapter tools, and +the CI and dormant-publisher roles request no capability or permission. +The current normalizer payloads only validate supplied records and return +observations; they do not execute a model, verifier, forge, or other adapter. +The GitHub forge normalizer remains a separate observation payload. Transport and +runtime wiring are not part of this inactive assembly. This is source data only. It is not selected, resolved, qualified, installed, or -activated, and it cannot invoke a model, use a credential, contact a provider, -publish, or touch a target. Run +activated, has no authority or qualification, and cannot invoke a model, use a +credential, contact a provider, publish, or touch a target. Run `bash scripts/test/default-profile-assembly.test.sh` for the focused proof. ## Inactive portable core v2 fake-forge contract diff --git a/RESTORE.md b/RESTORE.md index 6b04bbe..3e997a7 100644 --- a/RESTORE.md +++ b/RESTORE.md @@ -64,11 +64,11 @@ Restore the nine paths listed under “Inactive default profile assembly” in bash scripts/test/default-profile-assembly.test.sh ``` -The proof validates the profile and seven manifests, their exact main package -objects, the accepted Roadmap decision record, role separation, and empty tool -grants. Restoring these records does not select, resolve, qualify, install, or -activate the profile and performs no model, credential, provider, publish, or -target operation. +The proof validates the profile and six manifests, their exact main package +objects, the producer config contract, the accepted Roadmap decision record, role +separation, and empty tool requests. Restoring these records does not select, +resolve, qualify, install, or activate the profile; it grants no authority and +performs no model, credential, provider, publish, or target operation. --- diff --git a/ci/required-files.txt b/ci/required-files.txt index fb86969..2724168 100644 --- a/ci/required-files.txt +++ b/ci/required-files.txt @@ -276,11 +276,11 @@ scripts/test/default-deterministic-verifier-adapter.test.sh # Inactive default profile assembly profiles/default/v1/profile.json +profiles/default/v1/producer-config.json profiles/default/v1/manifests/claude-code-producer.json profiles/default/v1/manifests/codex-native-reviewer.json profiles/default/v1/manifests/deterministic-verifier.json profiles/default/v1/manifests/dormant-publisher.json profiles/default/v1/manifests/github-actions-ci.json -profiles/default/v1/manifests/github-forge.json profiles/default/v1/manifests/local-git-materializer.json scripts/test/default-profile-assembly.test.sh diff --git a/profiles/default/v1/manifests/claude-code-producer.json b/profiles/default/v1/manifests/claude-code-producer.json index e047f54..ab86c81 100644 --- a/profiles/default/v1/manifests/claude-code-producer.json +++ b/profiles/default/v1/manifests/claude-code-producer.json @@ -1 +1 @@ -{"body":{"adapter_version":"v1","offered_capabilities":["core.harness.produce.v1"],"offered_execution_kinds":["model"],"offered_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"offered_roles":["producer"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/claude-code-producer/v1/normalize.jq"},"mode":"100644","object_id":"8af4d80e04f6f3877861e55c216a5891830b03b6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.claude-code-producer.v1","kind":"adapter_manifest","schema_version":2} +{"body":{"adapter_version":"v1","config_contract_ref":{"decision_record_ref":{"content_id":"producer-config","media_type":"application/json","sha256":"ea076206d7f721aa4796c2a0830e95b3c7006703addc717240447c64ad589b61"},"purpose":"config-contract","scope_sha256":"ea076206d7f721aa4796c2a0830e95b3c7006703addc717240447c64ad589b61","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"producer-config","media_type":"application/json","sha256":"ea076206d7f721aa4796c2a0830e95b3c7006703addc717240447c64ad589b61"}}}},"offered_capabilities":["core.harness.produce.v1"],"offered_execution_kinds":["model"],"offered_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"offered_roles":["producer"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/claude-code-producer/v1/normalize.jq"},"mode":"100644","object_id":"8af4d80e04f6f3877861e55c216a5891830b03b6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.claude-code-producer.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/manifests/github-forge.json b/profiles/default/v1/manifests/github-forge.json deleted file mode 100644 index 74ce169..0000000 --- a/profiles/default/v1/manifests/github-forge.json +++ /dev/null @@ -1 +0,0 @@ -{"body":{"adapter_version":"v1","offered_capabilities":[],"offered_execution_kinds":["deterministic"],"offered_permissions":[],"offered_roles":["identity"],"offered_tools":[],"package_ref":{"location":{"kind":"path","value":"adapters/github-forge/v1/normalize.jq"},"mode":"100644","object_id":"feb4622bc4371dce337b1406062919ef2c2c5b49","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}}},"id":"adapter.github-forge.v1","kind":"adapter_manifest","schema_version":2} diff --git a/profiles/default/v1/profile.json b/profiles/default/v1/profile.json index 36dc0e4..5ee18cf 100644 --- a/profiles/default/v1/profile.json +++ b/profiles/default/v1/profile.json @@ -1 +1 @@ -{"body":{"bindings":[{"adapter_instance_id":"instance.ci","binding_id":"binding.ci","execution_boundary_id":"boundary.ci","execution_kind":"deterministic","manifest_ref":{"id":"adapter.github-actions-ci.v1","kind":"adapter_manifest","schema_version":2,"sha256":"a5cf4b1b94e32d850e3d056024fa2d2c3977b977fb08323e99b89f8c159baff3"},"package_ref":{"location":{"kind":"path","value":"adapters/github-actions-ci/v1/normalize.jq"},"mode":"100644","object_id":"2fad7d2d217a5704fcd4e2d1f559309aa832d16d","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.ci","requested_capabilities":[],"requested_permissions":[],"requested_tools":[],"role":"ci","skill_refs":[]},{"adapter_instance_id":"instance.forge","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"e31dd669bf048817b503928e51191809cf3a3718d328dc5ab8875a4fe9be2911","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-forge","media_type":"application/json","sha256":"e31dd669bf048817b503928e51191809cf3a3718d328dc5ab8875a4fe9be2911"}}}},"binding_id":"binding.forge","execution_boundary_id":"boundary.forge","execution_kind":"deterministic","manifest_ref":{"id":"adapter.local-git-materializer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"47c5884ca83597a09f1122467c9c0dfd3ea5b4e0256d2d52ae648167349bffe5"},"package_ref":{"location":{"kind":"path","value":"adapters/local-git-materializer/v1"},"mode":"040000","object_id":"277863b98b49e54e2cd826b3f32913fd49c51abf","object_type":"tree","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.forge","requested_capabilities":["core.forge.materialize-candidate.v2"],"requested_permissions":["core.perm.candidate-repository.write.v2","core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"forge","skill_refs":[]},{"adapter_instance_id":"instance.identity","binding_id":"binding.identity","execution_boundary_id":"boundary.identity","execution_kind":"deterministic","manifest_ref":{"id":"adapter.github-forge.v1","kind":"adapter_manifest","schema_version":2,"sha256":"a6290a480ab72b7deac2bc74bc63e35e4fa1dc952bab47de4b17ee9134476044"},"package_ref":{"location":{"kind":"path","value":"adapters/github-forge/v1/normalize.jq"},"mode":"100644","object_id":"feb4622bc4371dce337b1406062919ef2c2c5b49","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.identity","requested_capabilities":[],"requested_permissions":[],"requested_tools":[],"role":"identity","skill_refs":[]},{"adapter_instance_id":"instance.producer","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"b35cdd26196d8d93abe1c387cd4edcf9a130ddcc7a718b2431ddf94135eb19d5","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-producer","media_type":"application/json","sha256":"b35cdd26196d8d93abe1c387cd4edcf9a130ddcc7a718b2431ddf94135eb19d5"}}}},"binding_id":"binding.producer","execution_boundary_id":"boundary.producer","execution_kind":"model","manifest_ref":{"id":"adapter.claude-code-producer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"d849818eb02c96972e1ac90540fd1b00749384f07bb56ed66f0800f78537479e"},"model_request":{"effort_id":"high","model_id":"claude.sonnet","provider_id":"anthropic"},"package_ref":{"location":{"kind":"path","value":"adapters/claude-code-producer/v1/normalize.jq"},"mode":"100644","object_id":"8af4d80e04f6f3877861e55c216a5891830b03b6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.producer","prompt_ref":{"location":{"kind":"path","value":"routines/coder.md"},"mode":"100644","object_id":"b307b85339fbfc060aec59c625918a3f20707438","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"requested_capabilities":["core.harness.produce.v1"],"requested_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"producer","skill_refs":[]},{"adapter_instance_id":"instance.publisher","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"9d00187a85fea0021fac962ee13791a14420fb71f4c9e5dcb23a392d5cf0436e","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-publisher","media_type":"application/json","sha256":"9d00187a85fea0021fac962ee13791a14420fb71f4c9e5dcb23a392d5cf0436e"}}}},"binding_id":"binding.publisher","execution_boundary_id":"boundary.publisher","execution_kind":"deterministic","manifest_ref":{"id":"adapter.dormant-publisher.v1","kind":"adapter_manifest","schema_version":2,"sha256":"e780e0ceb0a305928d6c1fec127cfc6db0140cf2e48b3921e23e59d942419029"},"package_ref":{"location":{"kind":"path","value":"adapters/dormant-publisher/v1/normalize.jq"},"mode":"100644","object_id":"86ed0cd6b740a192b829044d7bcb7187e5f38422","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.publisher","requested_capabilities":[],"requested_permissions":[],"requested_tools":[],"role":"publisher","skill_refs":[]},{"adapter_instance_id":"instance.reviewer","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"a74f15bc7a469e74924725ab9c319ed9162f44fa12b3cf850798f8274c446b6a","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-reviewer","media_type":"application/json","sha256":"a74f15bc7a469e74924725ab9c319ed9162f44fa12b3cf850798f8274c446b6a"}}}},"binding_id":"binding.reviewer","execution_boundary_id":"boundary.reviewer","execution_kind":"model","manifest_ref":{"id":"adapter.codex-native-reviewer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"2f1ceaacd455e6cadc09f2762c6735eab48b91890240b6031af3db744a1175c4"},"model_request":{"effort_id":"high","model_id":"codex.review","provider_id":"openai"},"package_ref":{"location":{"kind":"path","value":"adapters/codex-native-reviewer/v1/normalize.jq"},"mode":"100644","object_id":"432f09f36f8c93076388e4a26dba56b6ee7a2bf9","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.reviewer","prompt_ref":{"location":{"kind":"path","value":"reviewer/codex-review.md"},"mode":"100644","object_id":"b757f78b26f926a6688077a81f5b68a37c1c6690","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"requested_capabilities":["core.review.change.v1"],"requested_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"reviewer","skill_refs":[]},{"adapter_instance_id":"instance.verifier","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"aa7447ee06f5e2a74124f2d0a9d96a4e7552e626ccbd6e60a5ba694331effe04","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-verifier","media_type":"application/json","sha256":"aa7447ee06f5e2a74124f2d0a9d96a4e7552e626ccbd6e60a5ba694331effe04"}}}},"binding_id":"binding.verifier","execution_boundary_id":"boundary.verifier","execution_kind":"deterministic","manifest_ref":{"id":"adapter.deterministic-verifier.v1","kind":"adapter_manifest","schema_version":2,"sha256":"58f65eeac7dc8292e48adf6e1d0e8235d5a19c92521993c74b7b3368bb3f36fe"},"package_ref":{"location":{"kind":"path","value":"adapters/deterministic-verifier/v1/normalize.jq"},"mode":"100644","object_id":"15fbf4648ee33b8c2fe15ab04357376313f900f6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.verifier","requested_capabilities":["core.verify.run.v1"],"requested_permissions":["core.perm.candidate.execute.v1","core.perm.evidence.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"verifier","skill_refs":[]}],"profile_version":"v1"},"id":"profile.default.v1","kind":"profile","schema_version":2} +{"body":{"bindings":[{"adapter_instance_id":"instance.ci","binding_id":"binding.ci","execution_boundary_id":"boundary.ci","execution_kind":"deterministic","manifest_ref":{"id":"adapter.github-actions-ci.v1","kind":"adapter_manifest","schema_version":2,"sha256":"a5cf4b1b94e32d850e3d056024fa2d2c3977b977fb08323e99b89f8c159baff3"},"package_ref":{"location":{"kind":"path","value":"adapters/github-actions-ci/v1/normalize.jq"},"mode":"100644","object_id":"2fad7d2d217a5704fcd4e2d1f559309aa832d16d","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.ci","requested_capabilities":[],"requested_permissions":[],"requested_tools":[],"role":"ci","skill_refs":[]},{"adapter_instance_id":"instance.forge","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"e31dd669bf048817b503928e51191809cf3a3718d328dc5ab8875a4fe9be2911","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-forge","media_type":"application/json","sha256":"e31dd669bf048817b503928e51191809cf3a3718d328dc5ab8875a4fe9be2911"}}}},"binding_id":"binding.forge","execution_boundary_id":"boundary.forge","execution_kind":"deterministic","manifest_ref":{"id":"adapter.local-git-materializer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"47c5884ca83597a09f1122467c9c0dfd3ea5b4e0256d2d52ae648167349bffe5"},"package_ref":{"location":{"kind":"path","value":"adapters/local-git-materializer/v1"},"mode":"040000","object_id":"277863b98b49e54e2cd826b3f32913fd49c51abf","object_type":"tree","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.forge","requested_capabilities":["core.forge.materialize-candidate.v2"],"requested_permissions":["core.perm.candidate-repository.write.v2","core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"forge","skill_refs":[]},{"adapter_instance_id":"instance.producer","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"b35cdd26196d8d93abe1c387cd4edcf9a130ddcc7a718b2431ddf94135eb19d5","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-producer","media_type":"application/json","sha256":"b35cdd26196d8d93abe1c387cd4edcf9a130ddcc7a718b2431ddf94135eb19d5"}}}},"binding_id":"binding.producer","config_ref":{"location":{"kind":"path","value":"profiles/default/v1/producer-config.json"},"mode":"100644","object_id":"369159a30c8a0026644c3716e7fc1132206e826c","object_type":"blob","revision":{"commit_id":"d97b8e36a2c305fa3888fafba0acda6b85fc93de","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"execution_boundary_id":"boundary.producer","execution_kind":"model","manifest_ref":{"id":"adapter.claude-code-producer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"ada221fd7186544a53ceb2f10e0bbe863eb0ef6ef54b407c65f58d7f21881bb3"},"model_request":{"effort_id":"high","model_id":"claude.sonnet","provider_id":"anthropic"},"package_ref":{"location":{"kind":"path","value":"adapters/claude-code-producer/v1/normalize.jq"},"mode":"100644","object_id":"8af4d80e04f6f3877861e55c216a5891830b03b6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.producer","prompt_ref":{"location":{"kind":"path","value":"routines/coder.md"},"mode":"100644","object_id":"b307b85339fbfc060aec59c625918a3f20707438","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"requested_capabilities":["core.harness.produce.v1"],"requested_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"producer","skill_refs":[]},{"adapter_instance_id":"instance.publisher","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"9d00187a85fea0021fac962ee13791a14420fb71f4c9e5dcb23a392d5cf0436e","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-publisher","media_type":"application/json","sha256":"9d00187a85fea0021fac962ee13791a14420fb71f4c9e5dcb23a392d5cf0436e"}}}},"binding_id":"binding.publisher","execution_boundary_id":"boundary.publisher","execution_kind":"deterministic","manifest_ref":{"id":"adapter.dormant-publisher.v1","kind":"adapter_manifest","schema_version":2,"sha256":"e780e0ceb0a305928d6c1fec127cfc6db0140cf2e48b3921e23e59d942419029"},"package_ref":{"location":{"kind":"path","value":"adapters/dormant-publisher/v1/normalize.jq"},"mode":"100644","object_id":"86ed0cd6b740a192b829044d7bcb7187e5f38422","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.publisher","requested_capabilities":[],"requested_permissions":[],"requested_tools":[],"role":"publisher","skill_refs":[]},{"adapter_instance_id":"instance.reviewer","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"a74f15bc7a469e74924725ab9c319ed9162f44fa12b3cf850798f8274c446b6a","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-reviewer","media_type":"application/json","sha256":"a74f15bc7a469e74924725ab9c319ed9162f44fa12b3cf850798f8274c446b6a"}}}},"binding_id":"binding.reviewer","execution_boundary_id":"boundary.reviewer","execution_kind":"model","manifest_ref":{"id":"adapter.codex-native-reviewer.v1","kind":"adapter_manifest","schema_version":2,"sha256":"2f1ceaacd455e6cadc09f2762c6735eab48b91890240b6031af3db744a1175c4"},"model_request":{"effort_id":"high","model_id":"codex.review","provider_id":"openai"},"package_ref":{"location":{"kind":"path","value":"adapters/codex-native-reviewer/v1/normalize.jq"},"mode":"100644","object_id":"432f09f36f8c93076388e4a26dba56b6ee7a2bf9","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.reviewer","prompt_ref":{"location":{"kind":"path","value":"reviewer/codex-review.md"},"mode":"100644","object_id":"b757f78b26f926a6688077a81f5b68a37c1c6690","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"requested_capabilities":["core.review.change.v1"],"requested_permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"reviewer","skill_refs":[]},{"adapter_instance_id":"instance.verifier","authority_ref":{"decision_record_ref":{"content_id":"roadmap","media_type":"text/markdown","sha256":"1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107"},"purpose":"authority","scope_sha256":"aa7447ee06f5e2a74124f2d0a9d96a4e7552e626ccbd6e60a5ba694331effe04","subject_ref":{"type":"artifact","value":{"type":"content","value":{"content_id":"authority-verifier","media_type":"application/json","sha256":"aa7447ee06f5e2a74124f2d0a9d96a4e7552e626ccbd6e60a5ba694331effe04"}}}},"binding_id":"binding.verifier","execution_boundary_id":"boundary.verifier","execution_kind":"deterministic","manifest_ref":{"id":"adapter.deterministic-verifier.v1","kind":"adapter_manifest","schema_version":2,"sha256":"58f65eeac7dc8292e48adf6e1d0e8235d5a19c92521993c74b7b3368bb3f36fe"},"package_ref":{"location":{"kind":"path","value":"adapters/deterministic-verifier/v1/normalize.jq"},"mode":"100644","object_id":"15fbf4648ee33b8c2fe15ab04357376313f900f6","object_type":"blob","revision":{"commit_id":"a637451d4b3fbef6b516a9c08f68c0dde46a7059","hash_algorithm":"sha1","repository_id":"repo.ystack"}},"principal_id":"principal.verifier","requested_capabilities":["core.verify.run.v1"],"requested_permissions":["core.perm.candidate.execute.v1","core.perm.evidence.write.v1","core.perm.target.read.v1"],"requested_tools":[],"role":"verifier","skill_refs":[]}],"profile_version":"v1"},"id":"profile.default.v1","kind":"profile","schema_version":2} diff --git a/scripts/test/default-profile-assembly.test.sh b/scripts/test/default-profile-assembly.test.sh index 90984fb..708ddec 100755 --- a/scripts/test/default-profile-assembly.test.sh +++ b/scripts/test/default-profile-assembly.test.sh @@ -2,11 +2,14 @@ # shellcheck disable=SC2016 set -euo pipefail export LC_ALL=C +umask 077 root=$(CDPATH='' cd -P -- "${BASH_SOURCE[0]%/*}/../.." && pwd -P) profile="$root/profiles/default/v1/profile.json" manifest_root="$root/profiles/default/v1/manifests" manifests=("$manifest_root"/*.json) +producer_manifest="$manifest_root/claude-code-producer.json" +producer_config="$root/profiles/default/v1/producer-config.json" roadmap="$root/ROADMAP.md" roadmap_sha='1466262c8994d637a02cc3503c35e3254ecce28479f9847589cb112e42b00107' package_commit='a637451d4b3fbef6b516a9c08f68c0dde46a7059' @@ -68,29 +71,94 @@ export PATH="$jq_runtime:$PATH" [ ! -L "$jq_bin" ] && [ "$(sha_file "$jq_bin")" = "$asset_sha" ] || fail jq-cache-digest [ "$(jq --version)" = jq-1.6 ] || fail jq-version -[ "${#manifests[@]}" -eq 7 ] || fail manifest-count + +history_repo="$tmp/history.git" +history_home="$tmp/home" +/bin/mkdir "$history_home" +/usr/bin/env -i HOME="$history_home" PATH=/usr/bin:/bin LC_ALL=C \ + GIT_CONFIG_NOSYSTEM=1 GIT_TERMINAL_PROMPT=0 \ + /usr/bin/git init --bare -q "$history_repo" +history_git() { + /usr/bin/env -i HOME="$history_home" PATH=/usr/bin:/bin LC_ALL=C \ + GIT_CONFIG_NOSYSTEM=1 GIT_TERMINAL_PROMPT=0 \ + /usr/bin/git -C "$history_repo" "$@" +} +origin_url=$(/usr/bin/git -C "$root" remote get-url origin) +[[ "$origin_url" =~ ^https://[^/@[:space:]]+/[^?#[:space:]]+$ ]] || + fail origin-url +history_git -c credential.helper= -c core.askPass= fetch -q --no-tags --depth=1 \ + "$origin_url" "+$package_commit:refs/ystack/package" +[ "$(history_git rev-parse 'refs/ystack/package^{commit}')" = "$package_commit" ] || + fail package-fetch +[ "$(history_git rev-list --count refs/ystack/package)" -eq 1 ] || + fail package-fetch-depth +[ -z "$(history_git for-each-ref --format='%(refname)' refs/tags)" ] || + fail package-fetch-tags + +[ "${#manifests[@]}" -eq 6 ] || fail manifest-count scripts_core="$root/scripts/core-contract.sh" +generation=$(/usr/bin/sed -n \ + "s/^PORTABLE_CORE_GENERATION='\(g-[0-9a-f]\{64\}\)'$/\1/p" "$scripts_core") +[[ "$generation" =~ ^g-[0-9a-f]{64}$ ]] || fail core-generation +modules="$root/core/v2/generations/$generation/modules" +[ -d "$modules" ] && [ ! -L "$modules" ] || fail core-modules "$scripts_core" validate-document "$profile" || fail profile-document for manifest in "${manifests[@]}"; do "$scripts_core" validate-document "$manifest" || fail "manifest-${manifest##*/}" done -ok 'profile and seven manifests pass core v2 document validation' +ok 'profile and six manifests pass core v2 document validation' + +producer_config_ref=$(jq -c '.body.bindings[] | select(.role=="producer") | .config_ref' "$profile") +[ "$(jq -r 'type' <<<"$producer_config_ref")" = object ] || fail producer-config-ref +config_commit=$(jq -r '.revision.commit_id' <<<"$producer_config_ref") +config_path=$(jq -r '.location.value' <<<"$producer_config_ref") +config_oid=$(jq -r '.object_id' <<<"$producer_config_ref") +config_mode=$(jq -r '.mode' <<<"$producer_config_ref") +config_type=$(jq -r '.object_type' <<<"$producer_config_ref") +[ "$config_path" = 'profiles/default/v1/producer-config.json' ] || fail producer-config-path +[ "$config_oid" = "$(git -C "$root" hash-object "$producer_config")" ] || + fail producer-config-blob +history_git -c credential.helper= -c core.askPass= fetch -q --no-tags --depth=1 \ + "$origin_url" "+$config_commit:refs/ystack/producer-config" +[ "$(history_git rev-parse 'refs/ystack/producer-config^{commit}')" = "$config_commit" ] || + fail producer-config-fetch +[ "$(history_git rev-list --count refs/ystack/producer-config)" -eq 1 ] || + fail producer-config-fetch-depth +config_record=$(history_git ls-tree "$config_commit" "$config_path") +[ "$config_record" = "$config_mode $config_type $config_oid"$'\t'"$config_path" ] || + fail producer-config-object +config_sha=$(sha_file "$producer_config") +jq -e --arg config_sha "$config_sha" ' + .body.config_contract_ref as $contract | + $contract.purpose == "config-contract" and + $contract.scope_sha256 == $config_sha and + $contract.decision_record_ref == { + content_id:"producer-config",media_type:"application/json",sha256:$config_sha + } and + $contract.subject_ref == { + type:"artifact", + value:{type:"content",value:{ + content_id:"producer-config",media_type:"application/json",sha256:$config_sha + }} + } +' "$producer_manifest" >/dev/null || fail producer-config-contract +ok 'the producer config contract and Git object are exact at their recorded revision' jq -e ' .id == "profile.default.v1" and .body.profile_version == "v1" and - (.body.bindings | length) == 7 and + (.body.bindings | length) == 6 and ([.body.bindings[].role] | sort) == - ["ci","forge","identity","producer","publisher","reviewer","verifier"] and - ([.body.bindings[].binding_id] | unique | length) == 7 and - ([.body.bindings[].adapter_instance_id] | unique | length) == 7 and - ([.body.bindings[].principal_id] | unique | length) == 7 and - ([.body.bindings[].execution_boundary_id] | unique | length) == 7 and + ["ci","forge","producer","publisher","reviewer","verifier"] and + ([.body.bindings[].binding_id] | unique | length) == 6 and + ([.body.bindings[].adapter_instance_id] | unique | length) == 6 and + ([.body.bindings[].principal_id] | unique | length) == 6 and + ([.body.bindings[].execution_boundary_id] | unique | length) == 6 and all(.body.bindings[] | select(.role|IN("forge","producer","publisher","reviewer","verifier")); has("authority_ref")) and ([.body.bindings[] | select(has("authority_ref"))] | length) == 5 and - all(.body.bindings[] | select(.role|IN("ci","identity")); - has("authority_ref") | not) and - all(.body.bindings[] | select(.role|IN("ci","identity","publisher")); + all(.body.bindings[] | select(.role=="ci"); + has("authority_ref") | not) and + all(.body.bindings[] | select(.role|IN("ci","publisher")); .requested_capabilities == [] and .requested_permissions == []) ' "$profile" >/dev/null || fail role-graph ok 'roles and protected boundaries are complete and separated' @@ -130,7 +198,7 @@ for manifest in "${manifests[@]}"; do oid=$(jq -r .body.package_ref.object_id "$manifest") mode=$(jq -r .body.package_ref.mode "$manifest") type=$(jq -r .body.package_ref.object_type "$manifest") - record=$(git -C "$root" ls-tree HEAD "$path") + record=$(history_git ls-tree "$commit" "$path") [ "$record" = "$mode $type $oid"$'\t'"$path" ] || fail "package-object-$id" done while IFS= read -r ref; do @@ -140,7 +208,7 @@ while IFS= read -r ref; do oid=$(jq -r .object_id <<<"$ref") mode=$(jq -r .mode <<<"$ref") type=$(jq -r .object_type <<<"$ref") - record=$(git -C "$root" ls-tree HEAD "$path") + record=$(history_git ls-tree "$commit" "$path") [ "$record" = "$mode $type $oid"$'\t'"$path" ] || fail "prompt-object-$path" done < <(jq -c '.body.bindings[] | .prompt_ref? // empty' "$profile") ok 'every manifest graph and selected Git object is exact' @@ -155,4 +223,155 @@ jq -e ' ' "$profile" >/dev/null || fail default-selection ok 'default model preferences are data and no tool is granted' +producer_source_repo="$tmp/producer-source" +/usr/bin/git init -q "$producer_source_repo" +/bin/mkdir "$producer_source_repo/manifests" +/bin/cp "$profile" "$producer_source_repo/profile.json" +/bin/cp "$manifest_root"/*.json "$producer_source_repo/manifests/" +/usr/bin/git -C "$producer_source_repo" add profile.json manifests +/usr/bin/git -C "$producer_source_repo" -c user.name=ystack-test \ + -c user.email=ystack-test@example.invalid commit -q -m producer-source +producer_source_commit=$(/usr/bin/git -C "$producer_source_repo" rev-parse HEAD) +producer_manifest_pairs="$tmp/producer-manifest-pairs.json" +producer_manifest_sources="$tmp/producer-manifest-sources.json" +for manifest in "${manifests[@]}"; do + name=${manifest##*/} + manifest_id=$(jq -r .id "$manifest") + manifest_sha=$(sha_file "$manifest") + IFS=$' \t' read -r manifest_mode manifest_type manifest_oid _ < <( + /usr/bin/git -C "$producer_source_repo" ls-tree "$producer_source_commit" "manifests/$name") + jq -S -c -n --arg id "$manifest_id" --arg commit "$producer_source_commit" \ + --arg path "manifests/$name" --arg mode "$manifest_mode" --arg type "$manifest_type" \ + --arg oid "$manifest_oid" --arg sha "$manifest_sha" ' + {id:$id,source:{source:{revision:{repository_id:"repo.default-profile-test", + hash_algorithm:"sha1",commit_id:$commit},location:{kind:"path",value:$path}, + object_type:$type,object_id:$oid,mode:$mode},value_format:"canonical-json",value_sha256:$sha}}' +done >"$tmp/producer-manifest-records.jsonl" +jq -S -s '.' "$tmp/producer-manifest-records.jsonl" >"$producer_manifest_sources" +for manifest in "${manifests[@]}"; do + manifest_sha=$(sha_file "$manifest") + jq -S -c --arg sha "$manifest_sha" '{content:.,sha256:$sha}' "$manifest" +done | jq -S -s '.' >"$producer_manifest_pairs" +IFS=$' \t' read -r producer_profile_mode producer_profile_type producer_profile_oid _ < <( + /usr/bin/git -C "$producer_source_repo" ls-tree "$producer_source_commit" profile.json) +producer_profile_source="$tmp/producer-profile-source.json" +jq -S -c -n --arg commit "$producer_source_commit" --arg mode "$producer_profile_mode" \ + --arg type "$producer_profile_type" --arg oid "$producer_profile_oid" ' + {source:{revision:{repository_id:"repo.default-profile-test",hash_algorithm:"sha1", + commit_id:$commit},location:{kind:"path",value:"profile.json"},object_type:$type, + object_id:$oid,mode:$mode},value_format:"canonical-json",value_sha256:""}' \ + >"$producer_profile_source" + +build_producer_input() { + local case_profile=$1 case_state=$2 case_input=$3 + local case_resolved="$case_input.resolved" case_request="$case_input.request" + local case_snapshot="$case_input.snapshot" case_profile_sha case_resolved_sha + local case_request_sha case_snapshot_sha + case_profile_sha=$(sha_file "$case_profile") + jq -L "$modules" -L "$root/scripts/test" -S -c -n \ + --slurpfile profile_doc "$case_profile" --slurpfile profile_source "$producer_profile_source" \ + --slurpfile manifests "$producer_manifest_pairs" --slurpfile sources "$producer_manifest_sources" \ + --arg profile_sha "$case_profile_sha" ' + import "portable-core-stage-request-fixtures" as fixture; + def present($value): {state:"present",value:$value}; + def absent: {state:"absent"}; + def source_value($source;$format;$sha): + {source:$source,value_format:$format,value_sha256:$sha}; + def pair_for($id): first($manifests[0][] | select(.content.id==$id)); + def source_for($id): first($sources[0][] | select(.id==$id) | .source); + ($profile_source[0] | .value_sha256=$profile_sha) as $profile_source | + {schema_version:2,kind:"resolved_profile",id:"resolved.example",body:{ + profile_ref:{schema_version:2,kind:"profile",id:$profile_doc[0].id,sha256:$profile_sha}, + profile_source:$profile_source,selection_ref:fixture::selection_scope, + repository_context_ref:fixture::repository_context_scope, + bindings:[$profile_doc[0].body.bindings[] as $binding | + pair_for($binding.manifest_ref.id) as $manifest | + {binding:$binding,adapter_implementation:{id:$manifest.content.id, + version:$manifest.content.body.adapter_version}, + manifest_source:source_for($binding.manifest_ref.id), + package_source:source_value($binding.package_ref;"raw-bytes";$profile_sha), + config_source:(if $binding | has("config_ref") then + present(source_value($binding.config_ref;"raw-bytes";$profile_sha)) else absent end), + prompt_source:(if $binding | has("prompt_ref") then + present(source_value($binding.prompt_ref;"raw-bytes";$profile_sha)) else absent end), + skill_sources:($binding.skill_refs | map(source_value(.;"raw-bytes";$profile_sha))), + tool_sources:($binding.requested_tools | map({tool_id:.tool_id, + package_source:source_value(.package_ref;"raw-bytes";$profile_sha), + config_source:.config_ref})) + }]}} + ' >"$case_resolved" + case_resolved_sha=$(sha_file "$case_resolved") + jq -L "$root/scripts/test" -S -c -n --arg resolved_sha "$case_resolved_sha" ' + import "portable-core-stage-request-fixtures" as fixture; + def v2: walk(if type=="object" and has("schema_version") then .schema_version=2 else . end); + fixture::request_doc("producer";$resolved_sha) | v2 + ' >"$case_request" + case_request_sha=$(sha_file "$case_request") + jq -L "$modules" -L "$root/scripts/test" -S -c -n \ + --slurpfile request_doc "$case_request" --slurpfile resolved_doc "$case_resolved" \ + --arg state "$case_state" --arg request_sha "$case_request_sha" \ + --arg resolved_sha "$case_resolved_sha" ' + import "stage_request" as request; + def present($value): {state:"present",value:$value}; + def absent: {state:"absent"}; + def fact($id;$value;$n): {state:"recorded",value:$value, + source_ref:{content_id:$id,media_type:"application/json",sha256:($n*64)}}; + request::expected_execution_projection($request_doc[0].body;$resolved_doc[0].body) as $projection | + ($resolved_doc[0].body.bindings[] | select(.binding.role=="producer") | .binding) as $binding | + {schema_version:1,kind:"claude_code_producer_snapshot",id:"snapshot.assembly",body:{ + attempt:{attempt_id:"attempt.assembly",attempt_number:1, + started_at:"2026-08-30T00:01:00Z",finished_at:"2026-08-30T00:02:00Z", + recorded_at:"2026-08-30T00:03:00Z"}, + execution:{performer:$projection.performer,actual_binding:$projection.actual_binding, + environment:$projection.environment,used_capability:$projection.used_capability, + metadata:{kind:"model",provider:fact("fact.provider";$binding.model_request.provider_id;"1"), + model:fact("fact.model";$binding.model_request.model_id;"2"), + snapshot:fact("fact.snapshot";"claude-code.v1";"3"), + effort:fact("fact.effort";$binding.model_request.effort_id;"4"), + prompt:fact("fact.prompt";$binding.prompt_ref;"5"),skills:fact("fact.skills";$binding.skill_refs;"6"), + tools:fact("fact.tools";$binding.requested_tools;"7")}}, + observed_at:"2026-08-30T00:04:00Z", + output:(if $state=="changed" then present({content_id:"producer.patch", + media_type:"text/x-diff",sha256:("a"*64)}) else absent end), + provider_metadata:{message:{state:"absent"}}, + request_ref:{schema_version:2,kind:"stage_request",id:$request_doc[0].id,sha256:$request_sha}, + resolved_profile_ref:{schema_version:2,kind:"resolved_profile",id:$resolved_doc[0].id,sha256:$resolved_sha}, + state:$state,target_revision:$request_doc[0].body.target_revision.value}} + ' >"$case_snapshot" + case_snapshot_sha=$(sha_file "$case_snapshot") + jq -S -c -n --slurpfile snapshot "$case_snapshot" --slurpfile request_doc "$case_request" \ + --slurpfile resolved_doc "$case_resolved" --slurpfile manifest_doc "$producer_manifest" \ + --arg snapshot_sha "$case_snapshot_sha" --arg request_sha "$case_request_sha" \ + --arg resolved_sha "$case_resolved_sha" --arg manifest_sha "$(sha_file "$producer_manifest")" ' + {snapshot:$snapshot[0],trust_context:{schema_version:1,kind:"adapter_trust_context", + id:"trust.assembly",body:{binding_id:"binding.producer",expected_attempt_id:"attempt.assembly", + expected_attempt_number:1,manifest:{content:$manifest_doc[0],sha256:$manifest_sha}, + request:{content:$request_doc[0],sha256:$request_sha}, + resolved_profile:{content:$resolved_doc[0],sha256:$resolved_sha}, + target_revision:$request_doc[0].body.target_revision.value, + verified_snapshot:{content:$snapshot[0],sha256:$snapshot_sha}}}} + ' >"$case_input" +} + +producer_normalizer="$root/adapters/claude-code-producer/v1/normalize.jq" +build_producer_input "$profile" changed "$tmp/producer-changed.input" +jq -L "$modules" -S -c -f "$producer_normalizer" "$tmp/producer-changed.input" \ + >"$tmp/producer-changed.output" || fail producer-normalizer-changed +jq -e '.state=="changed" and .observation.binding.config_ref.state=="present"' \ + "$tmp/producer-changed.output" >/dev/null || fail producer-normalizer-changed-output +build_producer_input "$profile" no-change "$tmp/producer-no-change.input" +jq -L "$modules" -S -c -f "$producer_normalizer" "$tmp/producer-no-change.input" \ + >"$tmp/producer-no-change.output" || fail producer-normalizer-no-change +jq -e '.state=="no-change" and .observation.result.output_ref.state=="absent"' \ + "$tmp/producer-no-change.output" >/dev/null || fail producer-normalizer-no-change-output +jq -S -c 'del(.body.bindings[] | select(.role=="producer").config_ref)' "$profile" \ + >"$tmp/producer-missing-config.profile" +build_producer_input "$tmp/producer-missing-config.profile" changed "$tmp/producer-missing-config.input" +if jq -L "$modules" -S -c -f "$producer_normalizer" "$tmp/producer-missing-config.input" \ + >"$tmp/producer-missing-config.output" 2>"$tmp/producer-missing-config.error"; then + fail producer-normalizer-missing-config +fi +grep -Fq E_TRUST "$tmp/producer-missing-config.error" || fail producer-normalizer-missing-config-error +ok 'the assembled producer binding normalizes changed and unchanged snapshots and rejects a missing config' + printf 'default profile assembly: %s focused checks passed\n' "$pass"