Repository navigation
ISS-12714: Print write operation ids from scripts - #345
Merged
Merged
Conversation
- upload_artifact.py adds the server's operationReceipt to its JSON result for each document it creates or versions, ahead of response, and omits it when the response has none - cl-policy's direct-API fallback prints each write response's clop_ operation id on stderr in the same shell call, leaving stdout as it was - Tests for receipt present, absent and malformed, and for the unchanged output shapes; the cl-policy test runs the documented snippet - Bump platform to 1.1.6 and vibe to 1.0.82, with changelog entries Testing: pytest plugins/, ruff, pyright, plugin-manifests tests; both outputs checked against symphony-alpha's readShellOperationIds Risks: None identified; the new field and stderr line are additive
main shipped vibe 1.0.82, so this branch's cl-policy change moves to vibe 1.0.83, with the manifest version pin moved to its test.
shafty023
added a commit
that referenced
this pull request
Oct 26, 2026
#345 took 1.0.83 on main. Retire its 1.0.83 version pin and pin this release at 1.0.84.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
ISS-12714 (child of PRD-800, "Writes made outside the Closedloop MCP"). A write made from a shell or script is tied to a session only when its operation id appears in that call's recorded output. The server side shipped in symphony-alpha ISS-12552 (#9058): API and MCP write responses carry an optional
operationReceipt({ operationId: "clop_<uuid>", outcome }), present only while the org'sattribution-evidence-policyflag is on. This makes the two script-side write paths in this repo print that id.What changed
platform 1.1.6:
upload-artifactupload_artifact.pyadds a top-leveloperationReceiptfield to its JSON result for the document it creates (create-document) or versions (create-document-version). It reads the receipt from the MCP body root, or fromdatafor an enveloped body, the same lookup symphony-alpha'sfile-bug.mjsandstack-rank-apply.mjsuse, and passes it through as those scripts do.response, so a transcript that keeps only the head of a long result (Claude Code's persisted-output preview) still holds the id.SKILL.mdstep 5a reports the operation id when the output has one.vibe 1.0.83:
cl-policydirect-API fallbackPOST/PUT/PATCH/DELETE, keep the response in a variable, print it (or the usualjqfilter of it) on stdout, then print(.data? // .).operationReceipt.operationIdon stderr in the same shell call. Steps 7 to 9 are renumbered; nothing references them by number.Output compatibility
upload_artifact.py: the field is additive and omitted when there is no receipt, or when it is malformed (no stringoperationId). Without a receipt, the keys and their order are exactly what they were. Stdout is still one JSON document.cl-policy: stdout is byte-identical to the response or the caller's filter; the id goes to stderr. Claude Code records stderr in the shell tool result, which is what symphony-alpha's matcher reads (measured below); Codex is expected to as well and was not measured. With no receipt, a list response, or an error envelope, nothing extra is printed and the exit status is 0.Tests
plugins/platform/skills/upload-artifact/scripts/test_upload_artifact.py(new): receipt present for create and version (root anddatashapes), the id in the matcher'sclop_<uuid>form, field order, receipt absent or malformed (keys unchanged), andmain()printing one parseable JSON document through a stubbed MCP session. With the script change reverted, the receipt-present cases fail and the absent cases pass.plugins/vibe/tools/python/test_cl_policy_operation_receipt_contract.py(new): runs the SKILL.md snippet verbatim in bash (minus itscurlassignment) against REST, delete and root-shaped receipts, and against no-receipt, list, malformed and error responses, asserting stdout unchanged, stderr equal to the id or empty, and exit 0. Swapping the snippet's redirections makes the present cases fail.readShellOperationIds(packages/lib/harness/tool-result-facts.ts, identical to origin/mainadba5b00e6) viatsx; it returned theclop_id for create, version and the cl-policy snippet, and[]with no receipt.AC2: verified end to end on a local stack
Run on a local seeded symphony-alpha stack (origin/main 177d0deafe; own Postgres, API and MCP on localhost; seed
e2eprofile API key generated for the run and deleted after; no production endpoint or credential used), withattribution-evidence-policyforced on for the seeded org through the existing preview flag snapshot (feature_flag_snapshots), no code edits.upload_artifact.py(this branch) printedoperationReceipt.operationIdfor a create and a version; the cl-policy step 6 snippet left stdout unchanged and printed itsclop_id on stderr. All exited 0.list-artifact-linkson the local MCP then showed the session tied to both documents by those receipts (sessionEvidence.operations: creation and revision on one, creation on the other). Each receipt's principal is the session owner and its time falls inside its shell call's window.tool_resulttext, stdout first, so the cl-policy stderr line reaches symphony-alpha's matcher.Commands run
Results: ruff and pyright clean; plugin-manifests 6/6; the vibe node tests that read manifests or skill text (97/97);
pytest plugins/2502 passed, 3 skipped, and 4 failed. All 4 failures are inplugins/code/tools/python/test_install_script.py, whereinstall.shhit the test's 20 second subprocess timeout on this loaded machine (the whole file times out locally, even run alone). This branch does not touchinstall.shor thecodeplugin. Platform (9) and vibe (443) pass on their own.