Skip to content

feat(contracts): add result envelope v1 - #321

Draft
davida-ps wants to merge 1 commit into
davida-ps/metadata-contracts-v1from
davida-ps/result-envelope-contract-v1
Draft

feat(contracts): add result envelope v1#321
davida-ps wants to merge 1 commit into
davida-ps/metadata-contracts-v1from
davida-ps/result-envelope-contract-v1

Conversation

@davida-ps

@davida-ps davida-ps commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

User description

Summary

  • Define the closed, harness-neutral clawsec.result/v1 execution summary.
  • Register eight outcomes, stable reason codes, deterministic CLI exit codes, and subject/effect policies for all 22 canonical capabilities.
  • Add unbound validation plus exact-metadata bound validation that also binds the caller's expected executor, subject, and invocation.
  • Add synthetic contract fixtures and negative tests covering OpenClaw, Hermes, NanoClaw v2, PicoClaw, all three roles, and all eight outcomes.

Design boundary

This is only the base execution-report contract. A valid result reports what an executor claims happened; it is not an installation plan, receipt, authorization, attestation, advisory proof, guardian evidence, or suite aggregation proof.

Bound success therefore returns binding: "exact_metadata" but authorization: "unverified". Detailed evidence belongs in later typed composition, advisory, plan, receipt, and guardian contracts.

This PR intentionally contains no skill implementations, documentation changes, workflows, release changes, store publication, advisory state, receipt schema, suite composition, or guardian evidence. The NanoClaw fixtures are contract examples, not a NanoClaw v2 runtime-support claim.

Security behavior

  • Bind executor and component references to exact skill.json bytes by SHA-256.
  • Reject executor, subject, or invocation substitution against caller-supplied expected context.
  • Enforce strict harness scopes, role/family ownership, outcome/reason compatibility, and operation subject/effect classes.
  • Require explicit nanoclaw.checkout scope for NanoClaw package operations and identify the subject's declared host package tree for successful or confirmation results.
  • Treat effects as visible self-reported summaries, never as mutation proof or authorization.
  • Enforce byte-only input, a 1 MiB limit, 64-level nesting, fatal UTF-8, BOM rejection, duplicate-key rejection, deterministic diagnostics, a 64-diagnostic cap, and a 64-effect-summary cap.

Remote validation

Tested from a fresh isolated remote checkout of exact base commit 8216ac59ad01a3841416cd6cdbf97e939e686ebf, with SHA-256 parity for every changed file:

  • npm run test:result-envelope-contract
  • npm run test:metadata-contracts
  • node scripts/test-skill-lifecycle-semver.mjs
  • npx eslint . --ext .ts,.tsx,.js,.jsx,.mjs --max-warnings 0
  • npx tsc --noEmit
  • npm run build
  • git diff --check

An adversarial near-1-MiB, 9,000-effect input is rejected in roughly 0.1–0.15 seconds after removing the redundant superlinear object-uniqueness check. Three independent final audits reported no remaining P0/P1/P2 findings.

Stack and release status

  • Stacked on metadata-contract PR feat(contracts): add component metadata v1 #320.
  • Draft only.
  • Do not merge until the architecture, lifecycle SemVer, and shared design language are reviewed together.
  • No tags, releases, catalogs, or skill-store publication are part of this PR.

Generated description

Below is a concise technical summary of the changes proposed in this PR:
Define the closed clawsec.result/v1 execution envelope, along with the result-v1 schema and supporting registries for outcomes, reason codes, CLI exit codes, and operation/effect policy. Add the validate_clawsec_result_envelope validator and test-skill-result-envelope-contract harness to enforce exact metadata binding, invocation/context checks, parser hardening, and synthetic coverage across the supported harnesses and roles.

TopicDetails
Validation suite Add bound and unbound result validation plus contract tests that verify exact metadata, expected invocation context, and negative parser/security cases.
Modified files (5)
  • contracts/fixtures/result-v1/valid/core-doctor-error-unknown-version-nanoclaw-v2.json
  • contracts/fixtures/result-v1/valid/core-doctor-pass-nanoclaw-v2.json
  • package.json
  • scripts/ci/validate_clawsec_result_envelope.mjs
  • scripts/test-skill-result-envelope-contract.mjs
Latest Contributors(2)
UserCommitDate
David.a@prompt.securityfeat(contracts): add r...July 23, 2026
github-actions[bot]chore: update NVD/GHSA...July 21, 2026
Result contract Define the clawsec.result/v1 envelope and the registries that map outcomes, reason codes, exit codes, and per-operation effect policy.
Modified files (5)
  • contracts/exit-codes.json
  • contracts/result-operation-policy.json
  • contracts/result-outcomes.json
  • contracts/result-reason-codes.json
  • contracts/schemas/result/result-v1.schema.json
Latest Contributors(1)
UserCommitDate
David.a@prompt.securityfeat(contracts): add r...July 23, 2026
Review this PR on Baz | Customize your next review

Comment on lines +467 to +478
if (executorBinding) {
const operation = document.invocation.operation;
if (!executorBinding.skill.clawsec.provides.includes(operation)) {
addError(
errors,
"RESULT_OPERATION_NOT_DECLARED",
"/invocation/operation",
`executor metadata does not declare operation ${operation}`,
);
}

const harnessVersion = document.invocation.harness.version;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Duplicate version-range checks

validateBoundResultEnvelope repeats the same semver-range gate for executorBinding and subjectBinding, so the bound-validation path carries two copies of the version logic and any policy change has to be updated twice — should we move that check into a small local helper in scripts/ci/validate_clawsec_result_envelope.mjs?

Severity

Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
scripts/ci/validate_clawsec_result_envelope.mjs around lines 467-508 inside
validateBoundResultEnvelope, the harness version support-range check is duplicated for
executorBinding and subjectBinding with only the binding source and error code/path
differing. Refactor by extracting a small local helper function (e.g.,
validateHarnessVersionSupport) that takes (binding, label, errorCode, errorPath) and
encapsulates the shared gate: harnessVersion !== null && isStrictSemver(harnessVersion)
&& !versionIsInRange(harnessVersion, binding.skill.clawsec.supported_harness) &&
!SAFE_REFUSAL_OUTCOMES.has(document.outcome). Then call this helper in both places to
ensure the logic lives in one place and behavior remains identical.

Comment on lines +1611 to +1615
function addError(errors, code, errorPath, message) {
const candidate = {
code: sanitizeDiagnosticText(code),
path: sanitizeDiagnosticText(errorPath || "/"),
message: sanitizeDiagnosticText(message),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Duplicated validator CLI plumbing

addError is duplicating the sorting, JSON-output, and exit-code plumbing already in scripts/ci/validate_clawsec_metadata.mjs:625-718, so changes to truncation, formatting, or CLI flags have to be made in two validators — should we move that shared logic into a helper module and keep only the result-specific checks here?

Severity

Want Baz to fix this for you? Activate Fixer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant