CAP v2.17.0 promotion capstone: version-consistency guard, claim truth, dashboard wire-contract fix - #410
Conversation
Adds a platform-neutral checker under tools/scripts that requires the root module, the nested sdk module, and the CI CAP checkout (CAP_REV / CAP_HANDSHAKE_CAP_SHA) to agree on one exact stable CAP tag, rejects pseudo-versions and CAP replace directives, and binds the configured tag to its immutable release commit through the knownCAPTagCommits table (currently v2.17.0 -> e580c670d54a7563c749835c7dd09d81f116c823, the promoted release this capstone freezes). Line-anchored patterns normalize CRLF so the test behaves identically on autocrlf (Windows) and LF working trees, unlike the neighboring toolchain tests. Every rule is proven to fire by a dedicated wrong-fixture test (pseudo-version, root/sdk skew, replace directive, CI SHA mismatch, unknown tag, tag/commit binding, missing requirement, single-line require form, CRLF). go test ./tools/scripts/ -run 'CAPConsistency|RepositoryCAPVersionConsistency': ok (11 tests). Signed-off-by: Yaron Torgeman <yaront1111@gmail.com>
Current-support sections no longer misstate the shipped CAP dependency: - AGENT_PROTOCOL / CORE / sdk-reference / backend feature matrix headings and claims now use introduction-provenance phrasing (introduced in CAP v2.13.1 / pinned CAP SDK) instead of implying the current dependency is v2.13.1 or v2.9.0; explicitly historical sections (CAP v2.9.0 changes, boundary hardening) are unchanged. - sdk/runtime alias-group comments clarified as introduction markers (introduced with CAP v2.5.2 / v2.5.3), not currency claims. - CHANGELOG records the v2.17.0 promotion, the new cross-file version consistency test, and explicitly documents that interop task-674 surfaces (TraceContext/WorkflowEvent/A2A/MCP) are NOT part of v2.17.0. N/A with grep evidence: deploy/, docker-compose*.yml, and cordum-helm/ contain no CAP version claims. dashboard/src/api/types.ts is handled by the dedicated dashboard step. Verified: go build ./... in sdk module; go vet ./runtime; go test ./tools/scripts ok. Signed-off-by: Yaron Torgeman <yaront1111@gmail.com>
Verification against the pinned CAP proto (proto/cordum/agent/v1/job.proto at v2.17.0) showed the dashboard's hand-written ErrorCode numeric table had drifted from the wire values it decodes: 102-104 and the entire 200-range, 302, and the 400-range carried wrong names, so ErrorCodeBadge mislabeled real backend error_code_enum values (e.g. wire 200 JOB_TIMEOUT rendered as "Job: Not Found"). AlertSeverity was verified correct. - ErrorCode now matches the protocol name-for-name and value-for-value; errorCodeLabel updated accordingly. Category ranges were already correct. - Stale "matches CAP v2.5.2" comments replaced with non-version provenance pointing at the proto file and the new contract test. - New src/api/errorCodeContract.test.ts pins every name/value pair plus label and category behavior (written first and observed RED: 2 failed / 2 passed against the drifted table). Dashboard rail (vs branch-point baseline tsc 0 errors, vitest 247/2111, build ok): tsc --noEmit exit 0 with 0 errors; vitest 248 files / 2115 tests passed (delta = this contract test); npm run build exit 0 in 4.97s. Signed-off-by: Yaron Torgeman <yaront1111@gmail.com>
📝 WalkthroughWalkthroughCAP v2.17.0 promotion adds repository-wide version consistency checks, aligns dashboard error-code mappings with CAP wire values, and updates changelog, documentation, and runtime comments. ChangesCAP promotion and contract alignment
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@dashboard/src/api/types.ts`:
- Around line 610-631: The errorCodeLabel function does not explicitly label the
valid ErrorCode.UNSPECIFIED value, and its contract test lacks zero-value
coverage. In dashboard/src/api/types.ts lines 610-631, add an
ErrorCode.UNSPECIFIED case with the intended human-readable label; in
dashboard/src/api/errorCodeContract.test.ts lines 39-47, assert that zero maps
to this label.
In `@docs/sdk-reference.md`:
- Around line 687-689: Update the CAP provenance in the “CAP Re-exported Types”
section and the Config.Logger/Config.Metrics documentation: attribute runtime
and observability aliases according to their introductions in
sdk/runtime/runtime.go, distinguishing CAP v2.5.2 from v2.5.3 instead of
applying CAP v2.13.1 universally. Apply the corresponding correction at the
Config fields location as well.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e8c7174b-adda-427e-91e4-14aca7d41eb7
📒 Files selected for processing (9)
CHANGELOG.mddashboard/src/api/errorCodeContract.test.tsdashboard/src/api/types.tsdocs/AGENT_PROTOCOL.mddocs/CORE.mddocs/backend_feature_matrix.mddocs/sdk-reference.mdsdk/runtime/runtime.gotools/scripts/cap_version_consistency_test.go
| /** Human-readable label for an ErrorCode value. */ | ||
| export function errorCodeLabel(code: number): string { | ||
| switch (code) { | ||
| case ErrorCode.PROTOCOL_VERSION_MISMATCH: return "Protocol: Version Mismatch"; | ||
| case ErrorCode.PROTOCOL_INVALID_PACKET: return "Protocol: Invalid Packet"; | ||
| case ErrorCode.PROTOCOL_MALFORMED_PACKET: return "Protocol: Malformed Packet"; | ||
| case ErrorCode.PROTOCOL_UNKNOWN_PAYLOAD: return "Protocol: Unknown Payload"; | ||
| case ErrorCode.PROTOCOL_SIGNATURE_INVALID: return "Protocol: Signature Invalid"; | ||
| case ErrorCode.PROTOCOL_TIMEOUT: return "Protocol: Timeout"; | ||
| case ErrorCode.PROTOCOL_RATE_LIMITED: return "Protocol: Rate Limited"; | ||
| case ErrorCode.JOB_NOT_FOUND: return "Job: Not Found"; | ||
| case ErrorCode.JOB_ALREADY_COMPLETED: return "Job: Already Completed"; | ||
| case ErrorCode.PROTOCOL_SIGNATURE_MISSING: return "Protocol: Signature Missing"; | ||
| case ErrorCode.JOB_TIMEOUT: return "Job: Timeout"; | ||
| case ErrorCode.JOB_CANCELLED: return "Job: Cancelled"; | ||
| case ErrorCode.JOB_PERMISSION_DENIED: return "Job: Permission Denied"; | ||
| case ErrorCode.JOB_RESOURCE_EXHAUSTED: return "Job: Resource Exhausted"; | ||
| case ErrorCode.JOB_PERMISSION_DENIED: return "Job: Permission Denied"; | ||
| case ErrorCode.JOB_INVALID_INPUT: return "Job: Invalid Input"; | ||
| case ErrorCode.JOB_NOT_FOUND: return "Job: Not Found"; | ||
| case ErrorCode.JOB_DUPLICATE: return "Job: Duplicate"; | ||
| case ErrorCode.JOB_WORKER_UNAVAILABLE: return "Job: Worker Unavailable"; | ||
| case ErrorCode.SAFETY_DENIED: return "Safety: Denied"; | ||
| case ErrorCode.SAFETY_POLICY_VIOLATION: return "Safety: Policy Violation"; | ||
| case ErrorCode.SAFETY_OUTPUT_QUARANTINED: return "Safety: Output Quarantined"; | ||
| case ErrorCode.TRANSPORT_UNAVAILABLE: return "Transport: Unavailable"; | ||
| case ErrorCode.TRANSPORT_POOL_EXHAUSTED: return "Transport: Pool Exhausted"; | ||
| case ErrorCode.TRANSPORT_DELIVERY_FAILED: return "Transport: Delivery Failed"; | ||
| case ErrorCode.SAFETY_RISK_TAG_BLOCKED: return "Safety: Risk Tag Blocked"; | ||
| case ErrorCode.TRANSPORT_PUBLISH_FAILED: return "Transport: Publish Failed"; | ||
| case ErrorCode.TRANSPORT_SUBSCRIBE_FAILED: return "Transport: Subscribe Failed"; | ||
| case ErrorCode.TRANSPORT_CONNECTION_LOST: return "Transport: Connection Lost"; | ||
| default: return `Error ${code}`; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Label the defined UNSPECIFIED wire value.
ErrorCode.UNSPECIFIED currently falls through to Error 0, making a valid protocol value indistinguishable from an unknown code.
dashboard/src/api/types.ts#L610-L631: add an explicitUNSPECIFIEDlabel.dashboard/src/api/errorCodeContract.test.ts#L39-L47: assert the zero-value label.
Proposed fix
export function errorCodeLabel(code: number): string {
switch (code) {
+ case ErrorCode.UNSPECIFIED: return "Unspecified";
case ErrorCode.PROTOCOL_VERSION_MISMATCH: return "Protocol: Version Mismatch"; it("labels wire values with the matching category and name", () => {
+ expect(errorCodeLabel(0)).toBe("Unspecified");
expect(errorCodeLabel(200)).toBe("Job: Timeout");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /** Human-readable label for an ErrorCode value. */ | |
| export function errorCodeLabel(code: number): string { | |
| switch (code) { | |
| case ErrorCode.PROTOCOL_VERSION_MISMATCH: return "Protocol: Version Mismatch"; | |
| case ErrorCode.PROTOCOL_INVALID_PACKET: return "Protocol: Invalid Packet"; | |
| case ErrorCode.PROTOCOL_MALFORMED_PACKET: return "Protocol: Malformed Packet"; | |
| case ErrorCode.PROTOCOL_UNKNOWN_PAYLOAD: return "Protocol: Unknown Payload"; | |
| case ErrorCode.PROTOCOL_SIGNATURE_INVALID: return "Protocol: Signature Invalid"; | |
| case ErrorCode.PROTOCOL_TIMEOUT: return "Protocol: Timeout"; | |
| case ErrorCode.PROTOCOL_RATE_LIMITED: return "Protocol: Rate Limited"; | |
| case ErrorCode.JOB_NOT_FOUND: return "Job: Not Found"; | |
| case ErrorCode.JOB_ALREADY_COMPLETED: return "Job: Already Completed"; | |
| case ErrorCode.PROTOCOL_SIGNATURE_MISSING: return "Protocol: Signature Missing"; | |
| case ErrorCode.JOB_TIMEOUT: return "Job: Timeout"; | |
| case ErrorCode.JOB_CANCELLED: return "Job: Cancelled"; | |
| case ErrorCode.JOB_PERMISSION_DENIED: return "Job: Permission Denied"; | |
| case ErrorCode.JOB_RESOURCE_EXHAUSTED: return "Job: Resource Exhausted"; | |
| case ErrorCode.JOB_PERMISSION_DENIED: return "Job: Permission Denied"; | |
| case ErrorCode.JOB_INVALID_INPUT: return "Job: Invalid Input"; | |
| case ErrorCode.JOB_NOT_FOUND: return "Job: Not Found"; | |
| case ErrorCode.JOB_DUPLICATE: return "Job: Duplicate"; | |
| case ErrorCode.JOB_WORKER_UNAVAILABLE: return "Job: Worker Unavailable"; | |
| case ErrorCode.SAFETY_DENIED: return "Safety: Denied"; | |
| case ErrorCode.SAFETY_POLICY_VIOLATION: return "Safety: Policy Violation"; | |
| case ErrorCode.SAFETY_OUTPUT_QUARANTINED: return "Safety: Output Quarantined"; | |
| case ErrorCode.TRANSPORT_UNAVAILABLE: return "Transport: Unavailable"; | |
| case ErrorCode.TRANSPORT_POOL_EXHAUSTED: return "Transport: Pool Exhausted"; | |
| case ErrorCode.TRANSPORT_DELIVERY_FAILED: return "Transport: Delivery Failed"; | |
| case ErrorCode.SAFETY_RISK_TAG_BLOCKED: return "Safety: Risk Tag Blocked"; | |
| case ErrorCode.TRANSPORT_PUBLISH_FAILED: return "Transport: Publish Failed"; | |
| case ErrorCode.TRANSPORT_SUBSCRIBE_FAILED: return "Transport: Subscribe Failed"; | |
| case ErrorCode.TRANSPORT_CONNECTION_LOST: return "Transport: Connection Lost"; | |
| default: return `Error ${code}`; | |
| /** Human-readable label for an ErrorCode value. */ | |
| export function errorCodeLabel(code: number): string { | |
| switch (code) { | |
| case ErrorCode.UNSPECIFIED: return "Unspecified"; | |
| case ErrorCode.PROTOCOL_VERSION_MISMATCH: return "Protocol: Version Mismatch"; | |
| case ErrorCode.PROTOCOL_MALFORMED_PACKET: return "Protocol: Malformed Packet"; | |
| case ErrorCode.PROTOCOL_UNKNOWN_PAYLOAD: return "Protocol: Unknown Payload"; | |
| case ErrorCode.PROTOCOL_SIGNATURE_INVALID: return "Protocol: Signature Invalid"; | |
| case ErrorCode.PROTOCOL_SIGNATURE_MISSING: return "Protocol: Signature Missing"; | |
| case ErrorCode.JOB_TIMEOUT: return "Job: Timeout"; | |
| case ErrorCode.JOB_RESOURCE_EXHAUSTED: return "Job: Resource Exhausted"; | |
| case ErrorCode.JOB_PERMISSION_DENIED: return "Job: Permission Denied"; | |
| case ErrorCode.JOB_INVALID_INPUT: return "Job: Invalid Input"; | |
| case ErrorCode.JOB_NOT_FOUND: return "Job: Not Found"; | |
| case ErrorCode.JOB_DUPLICATE: return "Job: Duplicate"; | |
| case ErrorCode.JOB_WORKER_UNAVAILABLE: return "Job: Worker Unavailable"; | |
| case ErrorCode.SAFETY_DENIED: return "Safety: Denied"; | |
| case ErrorCode.SAFETY_POLICY_VIOLATION: return "Safety: Policy Violation"; | |
| case ErrorCode.SAFETY_RISK_TAG_BLOCKED: return "Safety: Risk Tag Blocked"; | |
| case ErrorCode.TRANSPORT_PUBLISH_FAILED: return "Transport: Publish Failed"; | |
| case ErrorCode.TRANSPORT_SUBSCRIBE_FAILED: return "Transport: Subscribe Failed"; | |
| case ErrorCode.TRANSPORT_CONNECTION_LOST: return "Transport: Connection Lost"; | |
| default: return `Error ${code}`; |
📍 Affects 2 files
dashboard/src/api/types.ts#L610-L631(this comment)dashboard/src/api/errorCodeContract.test.ts#L39-L47
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@dashboard/src/api/types.ts` around lines 610 - 631, The errorCodeLabel
function does not explicitly label the valid ErrorCode.UNSPECIFIED value, and
its contract test lacks zero-value coverage. In dashboard/src/api/types.ts lines
610-631, add an ErrorCode.UNSPECIFIED case with the intended human-readable
label; in dashboard/src/api/errorCodeContract.test.ts lines 39-47, assert that
zero maps to this label.
| ## 8. CAP Re-exported Types | ||
|
|
||
| The `sdk/runtime` package re-exports several types from the CAP v2.13.1 SDK for convenience. These are available under the `runtime` package without importing CAP directly. | ||
| The `sdk/runtime` package re-exports several types from the pinned CAP SDK for convenience (first introduced in CAP v2.13.1). These are available under the `runtime` package without importing CAP directly. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n 'introduced (with|in) CAP|CAP v2\.(5\.2|5\.3|13\.1)' \
docs/sdk-reference.md sdk/runtime/runtime.goRepository: cordum-io/cordum
Length of output: 646
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## docs/sdk-reference.md around cited lines"
sed -n '660,775p' docs/sdk-reference.md | nl -ba -v660
echo
echo "## sdk/runtime/runtime.go around cited lines"
sed -n '1,80p' sdk/runtime/runtime.go | nl -ba -v1
echo
echo "## All CAP version mentions in sdk/runtime/runtime.go"
rg -n 'CAP v2|v2\.5|v2\.13|runtime|re-export|Alias|type ' sdk/runtime/runtime.go docs/sdk-reference.mdRepository: cordum-io/cordum
Length of output: 238
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "## docs/sdk-reference.md around cited lines"
sed -n '660,775p' docs/sdk-reference.md | gawk '{printf "%6d\t%s\n", NR+659, $0}'
echo
echo "## sdk/runtime/runtime.go around cited lines"
sed -n '1,80p' sdk/runtime/runtime.go | gawk '{printf "%6d\t%s\n", NR, $0}'
echo
echo "## All CAP version mentions in sdk/runtime/runtime.go and docs/sdk-reference.md"
rg -n 'CAP v2|v2\.5|v2\.13|runtime|re-export|Alias|type ' sdk/runtime/runtime.go docs/sdk-reference.md || true
echo
echo "## SDK module files mentioning CAP dependency/version"
rg -n 'github\.com/.*CAP|CAP|sAP|sap|v2\.5|v2\.13|sdk/runtime' go.mod go.sum docs sdk/runtime || trueRepository: cordum-io/cordum
Length of output: 30346
Correct the CAP introduction-version attribution.
docs/sdk-reference.md attributes the re-exported runtime/observability types and the new Config.Logger/Config.Metrics fields to CAP v2.13.1, but sdk/runtime/runtime.go marks the relevant aliases as introduced in CAP v2.5.2 and v2.5.3. Split the provenance by type instead of using one blanket version.
📍 Affects 1 file
docs/sdk-reference.md#L687-L689(this comment)docs/sdk-reference.md#L759-L759
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/sdk-reference.md` around lines 687 - 689, Update the CAP provenance in
the “CAP Re-exported Types” section and the Config.Logger/Config.Metrics
documentation: attribute runtime and observability aliases according to their
introductions in sdk/runtime/runtime.go, distinguishing CAP v2.5.2 from v2.5.3
instead of applying CAP v2.13.1 universally. Apply the corresponding correction
at the Config fields location as well.
Lighthouse CI —
|
Bundle size reportSoft thresholds (warn-only): initial ≤ 400 KB raw / 120 KB gzip; total ≤ 3100 KB raw / 950 KB gzip.
⚠ Soft-threshold warnings
Warn-only: this PR is not blocked. Audit the regression before merging. |
SDK Conformance — last runGenerated: 2026-07-22T21:57:01.653Z Totals
Matrix
Overall: ✅ ALL GREEN — every SDK passed every fixture. |
Capstone residuals for the CAP v2.17.0 promotion (task-a24b53c5; core pins landed in #408 by @yaront1111). Frozen target: v2.17.0 @
e580c670d54a7563c749835c7dd09d81f116c823— a completed release: GitHub Release published 2026-07-22T20:01:47Z, all four publish workflows green, registries verified live (Go proxy Origin.Hash exact; npmcap-sdk-node@2.17.0sha512-4kAPiJeVI7I3…; PyPIcap-sdk-python/cordum-guard2.17.0 whl+sdist hashes recorded); CAP manifest promotion in cordum-io/cap#90 (42/42 checks green, awaiting admin merge).Commits
63faa18etest(cap): cross-file CAP version-consistency regression test (tools/scripts) — root+sdk+CI CAP_REV/CAP_HANDSHAKE_CAP_SHA must agree on one exact published tag/commit pair (knownCAPTagCommits binds v2.17.0→e580c670); rejects pseudo-versions and CAP replaces; CRLF-immune; every rule proven by a wrong-fixture test (11 tests).e6659096docs: current-support claims corrected to introduction-provenance phrasing (AGENT_PROTOCOL/CORE/sdk-reference/feature-matrix/runtime.go comments); CHANGELOG promotion entry incl. explicit exclusion of interop task-674 surfaces; historical sections retained; deploy/compose/cordum-helm confirmed CAP-version-free (grep evidence).7a8dc549fix(dashboard): ErrorCode enum had drifted from the wire protocol (102-104, whole 200-range, 302, 400-range mislabeled — e.g. wire 200 JOB_TIMEOUT rendered "Job: Not Found"). Aligned name-for-name/value-for-value withproto/cordum/agent/v1/job.proto; AlertSeverity verified already-correct; newerrorCodeContract.test.tspins the table (written first, observed RED 2/4, then GREEN 4/4).Evidence (full logs in task record)
-p 1 -count=3flake sweep all ok (scheduler 108.9s, gateway 230.3s, …).-raceunavailable (CGO off) — count=3 is the approved substitute.tests/handshakeinterop47 PASS (challenge→authenticate→result + 8 negatives × Go/Py/Node installed SDKs, real Redis by digest, embedded real NATS, CAP SHA enforced);tests/capproduction198 PASS / 5 pkgs (signed work/result; unsigned/tampered/expired/wrong-audience/wrong-session/replay/stale-attempt rejected before side effects; sealed ResourceRef). Full compose stack 8/8 healthy +-tags=integration97 ok.Review order: this PR is independent of cordum-io/cordum-packs (packs promotion PR); both depend conceptually on cordum-io/cap#90 for manifest truth.
🤖 Generated with Claude Code
Summary by CodeRabbit
Changed
Documentation