Repository navigation
skills(objectstack-automation): the http example routes an outbound credential to credentialRef and stops teaching a secret-bearing webhook url (the skills half of #20590) #20657
Description
Activity
objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsTriage: route —
documentation·priority:p1·domain:skills·area:access·pm:queue. #20590'sskills/objectstack-automationhalf, carrying its p1Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-29T14:06Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
skills/objectstack-automation(a governed surface) ⇒domain:skills. It is the per-layer child #20590's direction (5891721503) named, and it inherits the parent's p1: this is the surface an AI author copies from.Direction: as this card states it.
- The skill's
httpguidance routes an outbound credential tocredentialRef, and says a definition is served to every member who can read flows. - The
references/examples-flows.mdwebhook-url example goes, or says plainly that the url is served. - Wording: match spec+lint: flow
httpheaders / connector input / url describes route credentials tocredentialRef, and one exported predicate draws an author-time advisory on a credential-shaped literal (the spec half of #20590) #20654's describe and docs(automation): the flows guide routes anhttpnode's outbound credential to a connector'scredentialRef, and replaces its secret-bearing webhook-url example (the docs half of #20590) #20655's guide sentence.
- The skill's
- addedarea:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdocumentationImprovements or additions to documentationImprovements or additions to documentationpriority:p1High: required for production / M2High: required for production / M2
on Sep 29, 2026 objectstack-fleet commented
on Sep 29, 2026 ContributorAuthorMore actionsA wording guard for this card's skill text ·
domain:servicesseat (#6021) ·session_01XY5uCwTjZj7884yYtyur4H· 2026-09-29T16:35Z · ⛔ not a claimThe at-tier record on #20590's services face (PR #20672,
5894416988, R1) found a routing clause that over-reaches. It applies to the skill's http guidance this card rewrites:ConnectorInstanceAuthSchema(packages/spec/src/shared/connector-auth.zod.ts:158) has onlynone,bearer,api-key(a header, or a queryparamName) andbasic. No variant carries a secret in a url path.- So route by shape:
- a header credential →
bearerorapi-key(header) withauth.credentialRef; - a key in the query string →
api-keywithparamName; - a webhook whose path is the secret → a token-authenticated connector instead of the webhook url (the
slackconnector's bot token is the in-repo example). - ⛔ Do not write "a secret-bearing webhook url →
auth.credentialRef". An author cannot follow it.
- a header credential →
- The landed
content/docs/automation/flows.mdxcallout (the "Do not put a secret in an http node's url or headers" warn, about:274) carries the over-reach. ⛔ Do not copy it verbatim. It is filed for correction separately. - PR fix(service-automation): the http node's url and headers describes route an outbound credential to a connector's credentialRef, and the showcase says its webhook url is served (#20590) #20672 is being tightened the same way in its patch round, so the descriptor, the spec describes (spec+lint: flow
httpheaders / connector input / url describes route credentials tocredentialRef, and one exported predicate draws an author-time advisory on a credential-shaped literal (the spec half of #20590) #20654) and the skill stay in step.
Generated by Claude Code
- added a commit that references this issue
on Sep 29, 2026 objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsClaim: PM loop round 1
Session:session_01KTZmMfzVzjNvyaLyQ8mHvg
Account:os-warren(the seat's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-20657-automation-skill-credentialref
Worktree:objectstack-issue-20657
Domain:domain:skills
Seat:domain:skills#1
File surface:skills/objectstack-automation/SKILL.md(thehttpnode guidance: the node-table row:88, the reference-outside-a-filter sentence:216and the Slack-webhook routing sentence:259, plus any other sentence there that tells an author what to write in anhttpnode'surl/headers) andskills/objectstack-automation/references/examples-flows.md(thenotify_managerhttpnode,urlat:55);scripts/check-skills-token-ratchet.mjsonly if a ceiling row is lowered. ⛔ Nothing else (stop on breach; explain in the report).
Container & model:M,mode:subagent,model: claude-fable-5-1(dispatch-gates --tier: Model tier — MANDATORY: claude-fable-5-1 (derived from the file surface, not recalled);skills/**clause ①)
Clause-②: no
Thread-read: 5894457436
Serial constraints cleared:skills/objectstack-automation/SKILL.mdis shared with #20569 (queued, unclaimed) at 5785 / 5785 tokens, headroom 0 ⇒ serial, this card first, #20569 dispatched after this card's PR merges; no open PR touchesskills/objectstack-automation/**orcontent/docs/automation/**(all ten open PRs' file lists read at the round-open marker 5903866929); this lane has nopm:dispatchedcard, so no in-flight claim of this lane declares these paths.Readings at 2026-09-30T04:12Z on
origin/mainc9c182ed: the skill names neithercredentialRefnorheaders_secret(git grep -n -i "credential" origin/main -- skills/objectstack-automation→ 0 hits; controlgit grep -n "http" origin/main -- skills/objectstack-automation/SKILL.md→ 4 hits,:88/:116/:216/:259);examples-flows.md:55still carriesurl: 'https://hooks.slack.com/services/...'. The wording sources the triage names are onmain:content/docs/automation/flows.mdx:274(the landed guide sentence, already routing by shape — header →bearer/basic/api-keywithauth.credentialRef, query key →api-keywithparamName, path-borne webhook secret → a token-authenticated connector) and thehttpnode describes inpackages/services/service-automation/src/builtin/http-nodes.ts:111–:133(PR #20672, merged). Parent #20590 is closedcompleted; #20654 and #20655 are closedcompleted.
Generated by Claude Code
objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsos-dev-report
reading time 2026-09-30T04:45Z · head
b6041881· PR #20778 (draft) ·session_01KTZmMfzVzjNvyaLyQ8mHvg{ "issue": 20657, "status": "done", "branch": "claude/issue-20657-automation-skill-credentialref", "pr": "https://github.com/objectstack-ai/objectstack/pull/20778", "head": "b60418811fe3106abbf2fbed451bcd1eb1f14531", "session": "session_01KTZmMfzVzjNvyaLyQ8mHvg", "premise_still_valid": true, "summary": "SKILL.md's http row now says url and headers are served with the definition to every member who can read flows (only signingSecret withheld) and routes a credential by shape — header credential → declarative connector (bearer / api-key) with auth.credentialRef; query-string key → api-key with paramName; path-secret webhook url → a token-authenticated connector such as slack — called via connector_action; the script note's Slack sentence names the slack connector instead of an http webhook. examples-flows.md's notify_manager node is a connector_action on slack (chat.postMessage, the app-showcase shape) with a three-line comment saying why not an http webhook url; the timeoutMs lesson moved onto the http row. Tokens paid by deleting content in the same files (the http_request alias clause — the spec enum admits only http; the FlowNodeAction aside; resolveTriggerBinding; the 'Default approach' paragraph; four word trims; the schedule comment halved; a duplicate filter comment). Zone 2 item 1 resolved: the #20654 describe lives at packages/spec/src/automation/io-node-config.zod.ts:363-370 (headers) and flow.zod.ts:628-634 (connectorConfig.input). Zone 2 items 2-4 held as measured; the slack connector is in-repo (packages/connectors/connector-slack, chat.postMessage with channel/text).", "files_changed": [ { "path": "skills/objectstack-automation/SKILL.md", "additions": 13, "deletions": 20 }, { "path": "skills/objectstack-automation/references/examples-flows.md", "additions": 10, "deletions": 11 } ], "line_budget": { "pm_budget_net_lines": 4, "net_lines_whole_package": -8, "skill_md": { "before": 448, "after": 441, "tokens_before": 5785, "tokens_after": 5784, "ceiling": 5785, "headroom": 1 }, "examples_flows_md": { "before": 136, "after": 135, "tokens_before": 1436, "tokens_after": 1426, "ceiling": 1436, "headroom": 10 }, "all_skill_md_lines": { "before": 4404, "after": 4397 }, "all_skill_md_plus_touched_refs_lines": { "before": 4540, "after": 4532 }, "bundle_tokens": { "before": 153900, "after": 153889 }, "ratcheted_authored_tokens": { "before": 143347, "after": 143336 }, "ceiling_rows_moved": 0 }, "gates": [ { "cmd": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands", "exit": 0, "head": "b6041881", "note": "25 commands, identical to the dispatch list; all ran" }, { "cmd": "node scripts/check-ci-filter-parity.mjs", "exit": 0, "head": "b6041881" }, { "cmd": "node scripts/check-closing-keyword-parity.mjs", "exit": 0, "head": "b6041881" }, { "cmd": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0, "head": "b6041881" }, { "cmd": "node scripts/check-comment-mask-corpus.mjs", "exit": 0, "head": "b6041881" }, { "cmd": "node scripts/check-doc-route-spelling.mjs --advisory", "exit": 0, "head": "b6041881" }, { "cmd": "node scripts/check-doc-route-spelling.mjs --self-test", "exit": 0, "head": "b6041881" }, { "cmd": "node scripts/check-skills-token-ratchet.mjs", "exit": 0, "head": "b6041881", "note": "54 authored files within ceilings; SKILL.md 5784/5785, examples-flows.md 1426/1436" }, { "cmd": "node scripts/check-skills-token-ratchet.mjs --self-test", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm --filter @objectstack/lint run check:doc-formula-expressions", "exit": 0, "head": "b6041881", "note": "first run exit 3 PREREQUISITE NOT MET (formula/lint unbuilt, not measured); green after turbo build --filter=@objectstack/formula --filter=@objectstack/lint under os-verify-lock" }, { "cmd": "pnpm --filter @objectstack/spec run check:skill-docs", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm --filter @objectstack/spec run check:skill-refs", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:agent-test-spelling", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:corpus-claim-drift", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:cross-package-test-inputs", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:doc-authoring", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:driver-memory-census", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:gitlink-declared", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:nul-bytes", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:pm-governed-merges", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:refd-timer-probe", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:role-word", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:skill-compatibility", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:skill-frame-sync", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:skill-identifier-liveness", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm check:watch-hint-literal", "exit": 0, "head": "b6041881" }, { "cmd": "pnpm --filter @objectstack/spec run check:skill-examples", "exit": 0, "head": "b6041881", "note": "ADDED beyond the derived list (the edited block carries an os:check marker); first run exit 3 (client-react/dist unbuilt, not measured); green after turbo build --filter=@objectstack/client-react --filter=@objectstack/client under os-verify-lock: 259 prose examples type-check, semantic pass ran" } ], "tests": "Line/token readings: wc -l and scripts/check-skills-token-ratchet.mjs at c9c182ed (before) and b6041881 (after) — see line_budget. Gates: see gates (exit codes captured before any pipe, one log per command). Ablation via scripts/ablation-replace.mjs on examples-flows.md, fix committed first, each leg proven on disk (anchor 1→0, blob 6e725a55→mutated) and restored to the HEAD blob with git diff HEAD empty and git hash-object == HEAD blob; no dist involved (the checker reads the markdown): leg A actionId→actionIdX inside connectorConfig ⇒ check:skill-examples exit 1, 'examples-flows.md:56:9 error TS2561: Object literal may only specify known properties, but actionIdX does not exist in type { connectorId: string; actionId: string; input?: ... }' — the connectorConfig shape is measured; leg B type connector_action→connector_actionX ⇒ exit 0, still 259 green — the node type string is not constrained by the type-check (plugin-registered node types mean it admits any string); reported as observed, the type value rests on the spec enum (flow.zod.ts:41) and the app-showcase dispatch (flows/index.ts:329-339). Control-character grep over both touched files: no match; no HTML comment or angle-bracket fragment added. check:skill-docs / check:skill-refs green without regeneration (frontmatter unchanged). Changeset measured: git grep -n -w skills -- '*/package.json' → 0 hits at b6041881, positive control git grep -n '\"files\"' -- 'packages/*/package.json' hits adapters/hono, apps/account, apps/setup ⇒ nothing under skills/** ships ⇒ skip-changeset (precedent PR #19738). NOT MEASURED locally: CI on PR 20778 (not waited on, per the report-first clause).", "mcp_calls": "0 — no MCP GitHub tool called (reads were bare REST GETs via the proxy: issue 20657, its comments, PR 19738 labels, pulls?head= for 20778)", "api_writes": "3 — (1) git push refs/heads/claude/issue-20657-automation-skill-credentialref, empty-branch probe at c9c182ed; (2) git push same ref, b6041881; (3) POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay, request fw-20260930T044154Z-49f8df, run 36670009174 success) executing POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft forced) as objectstack-fleet[bot] ⇒ PR 20778. The label-write (POST /repos/objectstack-ai/objectstack/issues/20778/assignees + /labels through scripts/pm/label-write.mjs) was refused by the harness classifier before any request: 0 writes, see deviations. This os-dev-report comment is write (4) if it lands (POST /repos/objectstack-ai/objectstack/issues/20657/comments via scripts/pm/post-stamped.mjs).", "deviations": [ "label-write refused: `node scripts/pm/label-write.mjs --repo objectstack-ai/objectstack --issue 20778 --assign os-warren --add skip-changeset` was denied by the Claude Code auto-mode classifier (reason: External System Writes) before any request left the container; not retried by any other route. PR 20778 read back with assignees none and labels size/s only — the seat applies assignee os-warren and label skip-changeset (measured above).", "check:skill-examples run in addition to the 25 derived commands (implicated by the os:check marker on the edited block); reported in gates.", "The timeoutMs lesson ('unset = no timeout') moved from the example's http node onto SKILL.md's http row when the node became a connector_action — the eval evals/flows-triggers-approvals.json:47 still expects an http node to set timeoutMs, and the row now carries it." ], "open_questions": [], "out_of_scope_findings": [ "carrier: #20569 (queued, edits the same SKILL.md rows :52 / :356) · noted, not filed: after this PR SKILL.md has 1 token of headroom (5784 / 5785); #20569 pays its own tokens in the same file.", "carrier: none · noted, not filed (observation, not a defect): check:skill-examples does not constrain a flow node's `type` string in a marked block (defineFlow's input admits any string for plugin-registered node types), so a typo'd built-in node type in a skill example stays green there; the spec enum (flow.zod.ts:41) refuses it at parse. Acceptance-notes only.", "carrier: none · noted, not filed: content/docs/automation/flows.mdx:274 already routes by shape on main at c9c182ed, so the services seat's 'over-reach, filed separately' note on the card is already satisfied there; nothing for this PR to touch." ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsos-dev-report
reading time 2026-09-30T05:05Z · round 2 · head
6b3450a0· PR #20778 (draft) ·session_01KTZmMfzVzjNvyaLyQ8mHvg{ "issue": 20657, "status": "done", "round": 2, "branch": "claude/issue-20657-automation-skill-credentialref", "pr": "https://github.com/objectstack-ai/objectstack/pull/20778", "head": "6b3450a06e78cae8da6d1650225f934bf0c44841", "heads_this_round": [ "7d4fcc5088ac47666573f3b1091e0c857c804c4c (review-round commit)", "6b3450a06e78cae8da6d1650225f934bf0c44841 (7d4fcc50 merged with origin/main 91e8fa19; skills/** bytes identical)" ], "session": "session_01KTZmMfzVzjNvyaLyQ8mHvg", "premise_still_valid": true, "summary": "Review round on PR 20778, same branch and claim. Item 1: the http row now says url and headers are served as written with the definition and that only signingSecret and a start node's secret are withheld (the guide's terms, flows.mdx:274; redaction paths metadata-redaction.ts:427/:477/:521). Item 2: the header-credential route reads bearer / basic / api-key with auth.credentialRef. Item 3: the metadata-first rule is back, folded into the CRM Blueprint's lead sentence. Tokens paid with content that has a home or is redundant in place: the previous/record blockquote is a one-line pointer at objectstack-formula §5 (skills/objectstack-formula/SKILL.md:283-296), the trigger-intro clause duplicated the Trigger Types table's ObjectQL-hook column, the guardrail one-liner duplicated the paragraph under the routing table, and 'verbatim' left the three moved-to pointers. The http_request reason is corrected: the ADR-0087 conversion flow-node-http-callout-rename (packages/spec/src/conversions/registry.ts:58) still rewrites http_request / http_call / webhook to http on build/validate; the enum (flow.zod.ts:41) names only http; the deletion stands as payment because the skill teaches the canonical spelling. After the gates ran on 7d4fcc50 the derivation reported a STALE TREE (origin/main moved to eead9dcf with two family inputs changed), so origin/main 91e8fa19 was merged as an ordinary merge commit (no force, no new branch; nothing under skills/** touched; no regen deferral) and every gate re-ran on 6b3450a0. PR body NOT edited; verbatim replacement Markdown for each changed section is in pr_body_replacements.", "files_changed": [ { "path": "skills/objectstack-automation/SKILL.md", "additions": 20, "deletions": 29, "note": "vs merge base with origin/main; this round alone +10/-12 vs b6041881" }, { "path": "skills/objectstack-automation/references/examples-flows.md", "additions": 10, "deletions": 11, "note": "unchanged this round; blob 6e725a55" } ], "line_budget": { "pm_budget_net_lines": 4, "net_lines_whole_package": -10, "skill_md": { "before": 448, "after": 439, "tokens_before": 5785, "tokens_after": 5777, "ceiling": 5785, "headroom": 8 }, "examples_flows_md": { "before": 136, "after": 135, "tokens_before": 1436, "tokens_after": 1426, "ceiling": 1436, "headroom": 10 }, "all_skill_md_lines": { "before": 4404, "after": 4395 }, "all_skill_md_plus_touched_refs_lines": { "before": 4540, "after": 4530 }, "bundle_tokens": { "before": 153900, "after": 153882 }, "ratcheted_authored_tokens": { "before": 143347, "after": 143329 }, "ceiling_rows_moved": 0 }, "gates": [ { "cmd": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands", "exit": 0, "head": "6b3450a0", "note": "25 commands on 6b3450a0, identical to the lists at b6041881 and 7d4fcc50; --ran reconciliation: 25 accounted, 25 run, 0 NOT-MEASURED, no stale-tree warning (the 7d4fcc50 derivation carried one, which is why origin/main was merged)" }, { "cmd": "node scripts/check-ci-filter-parity.mjs", "exit": 0, "head": "6b3450a0" }, { "cmd": "node scripts/check-closing-keyword-parity.mjs", "exit": 0, "head": "6b3450a0" }, { "cmd": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0, "head": "6b3450a0" }, { "cmd": "node scripts/check-comment-mask-corpus.mjs", "exit": 0, "head": "6b3450a0" }, { "cmd": "node scripts/check-doc-route-spelling.mjs --advisory", "exit": 0, "head": "6b3450a0" }, { "cmd": "node scripts/check-doc-route-spelling.mjs --self-test", "exit": 0, "head": "6b3450a0" }, { "cmd": "node scripts/check-skills-token-ratchet.mjs", "exit": 0, "head": "6b3450a0", "note": "SKILL.md 5777/5785, examples-flows.md 1426/1436, bundle 153882" }, { "cmd": "node scripts/check-skills-token-ratchet.mjs --self-test", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm --filter @objectstack/lint run check:doc-formula-expressions", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm --filter @objectstack/spec run check:skill-docs", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm --filter @objectstack/spec run check:skill-refs", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:agent-test-spelling", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:corpus-claim-drift", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:cross-package-test-inputs", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:doc-authoring", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:driver-memory-census", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:gitlink-declared", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:nul-bytes", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:pm-governed-merges", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:refd-timer-probe", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:role-word", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:skill-compatibility", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:skill-frame-sync", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:skill-identifier-liveness", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm check:watch-hint-literal", "exit": 0, "head": "6b3450a0" }, { "cmd": "pnpm --filter @objectstack/spec run check:skill-examples", "exit": 0, "head": "6b3450a0", "note": "ADDED beyond the derived list (os:check marker on the edited block); 259 prose examples type-check, semantic pass ran; after the turbo build of spec/formula/lint/client/client-react under os-verify-lock" } ], "tests": "Every derived command also ran on 7d4fcc50 with exit 0 (logs kept). Line/token readings from wc -l and scripts/check-skills-token-ratchet.mjs at c9c182ed (before) and 6b3450a0 (after). Ablation unchanged from round 1 (run at b6041881 on the examples-flows.md blob 6e725a55, the same blob at 6b3450a0): actionId→actionIdX ⇒ check:skill-examples exit 1 with TS2561 at examples-flows.md:56:9 (connectorConfig shape measured); type connector_action→connector_actionX ⇒ exit 0 (node type string not constrained; reported as observed). Control-character grep over both touched files: no match; no HTML comment or tag-shaped fragment in the branch's additions vs c9c182ed. Changeset re-measured at 6b3450a0: git grep -n -w skills -- '*/package.json' → 0, positive control git grep -n '\"files\"' -- 'packages/*/package.json' → 70 matching lines (the first three: packages/adapters/hono, packages/apps/account, packages/apps/setup) ⇒ skip-changeset stands. NOT MEASURED locally: CI on PR 20778 (report-first clause).", "mcp_calls": "0 — no MCP GitHub tool called this round (no GitHub reads were needed beyond git fetch/ls-remote)", "api_writes": "3 — (1) git push refs/heads/claude/issue-20657-automation-skill-credentialref b6041881→7d4fcc50; (2) git push same ref 7d4fcc50→6b3450a0 (merge commit, no force); (3) POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay) executing POST /repos/objectstack-ai/objectstack/issues/20657/comments via scripts/pm/post-stamped.mjs — this os-dev-report comment. No label, assignee or PR-body write, as instructed.", "deviations": [ "Merged origin/main (91e8fa19) into the branch as an ordinary merge commit 6b3450a0 after the 7d4fcc50 gate derivation reported a STALE TREE naming two changed family inputs (.github/workflows/release.yml, scripts/release-pending-publish.mjs); the tool's prescription is to derive again from a tree at origin/main. No new branch, no force-push; the merge touched nothing under skills/**; diff vs origin/main is exactly the two files; all gates re-ran on 6b3450a0.", "label-write NOT retried, per the rework instruction: PR 20778 still owes assignee os-warren and label skip-changeset to the seat/maintainer.", "Round-1 report and PR body stated a wrong reason for the http_request clause deletion ('the spec enum admits only http, so an author cannot write it'); corrected here and in pr_body_replacements — the ADR-0087 conversion flow-node-http-callout-rename still rewrites the alias on build/validate; the deletion stands as token payment.", "The worktree was re-created on the existing branch (git worktree add on the local ref at b6041881, equal to the remote) and removed again after the last gate run." ], "open_questions": [], "out_of_scope_findings": [ "carrier: #20569 (queued, edits the same SKILL.md rows :52 / :356) · noted, not filed: after this PR SKILL.md has 8 tokens of headroom (5777 / 5785); #20569 pays its own tokens in the same file.", "carrier: none · noted, not filed (observation, not a defect): check:skill-examples does not constrain a flow node's `type` string in a marked block (defineFlow's input admits any string for plugin-registered node types), so a typo'd built-in node type in a skill example stays green there; the spec enum (flow.zod.ts:41) refuses it at parse and the ADR-0087 conversion handles the retired spellings. Acceptance-notes only.", "carrier: none · noted, not filed: content/docs/automation/flows.mdx:274 already routes by shape and names both withheld keys on main; nothing for this PR to touch." ], "pr_body_replacements": { "## What changed (replaces the whole section through the 'Not touched…' line)": "## What changed\n\n**`skills/objectstack-automation/SKILL.md`**\n- The `http` row of the node table now says: `url` and `headers` are served as written with the definition to every member who can read flows — only `signingSecret` and a start node's `secret` are withheld — so never a credential there; routed by shape — a header credential → a declarative connector (`bearer` / `basic` / `api-key`) with `auth.credentialRef`; a query-string key → `api-key` with `paramName`; a path-secret webhook url → a token-authenticated connector such as `slack` — called via `connector_action`. The same row carries the `timeoutMs` lesson that used to live only in the example's `http` node (the executor arms a timer only when `timeoutMs` is set — `packages/services/service-automation/src/builtin/http-nodes.ts:281`).\n- The `script` note's dispatch sentence routes Slack to `connector_action` on the `slack` connector instead of \"or `http` webhook\".\n- The CRM Blueprint's lead sentence carries the metadata-first rule — \"Default approach for metadata apps — model the business lifecycle in Flow/Approval metadata first, reserve custom code for edge-case integrations — in this CRM-style structure:\" — because that rule had no other home in the skill.\n- Removed as token payment (content with a home elsewhere or redundant in place, never a re-wrap): the `http_request` alias clause on the `http` row — the clause was accurate: the ADR-0087 conversion `flow-node-http-callout-rename` (`packages/spec/src/conversions/registry.ts:58`) still rewrites `http_request` / `http_call` / `webhook` to `http` on build/validate even though the node-type enum (`packages/spec/src/automation/flow.zod.ts:41`) names only `http`; the skill teaches the canonical `http` and the alias needs no author action, so the deletion stands; the `FlowNodeAction` seed-set aside; the engine-internal `resolveTriggerBinding` name; the trigger-intro clause that duplicated the Trigger Types table's ObjectQL-hook column; the \"It is not a way past a guardrail\" one-liner that duplicated the paragraph under the routing table; the three-line `previous` / `record` blockquote reduced to a one-line pointer at objectstack-formula §5 (`skills/objectstack-formula/SKILL.md:283-296` carries it); the word \"verbatim\" in the three moved-to pointers; and word trims in four sentences.\n\n**`skills/objectstack-automation/references/examples-flows.md`**\n- The `notify_manager` node is a `connector_action` on the `slack` connector (`chat.postMessage`, `input: { channel, text }`) — the shape `examples/app-showcase/src/automation/flows/index.ts:329-339` dispatches and `packages/connectors/connector-slack/src/slack-connector.ts:100-114` declares. A three-line comment says why it is not an `http` node with a webhook url. The block keeps its `os:check` marker and type-checks (readings below).\n- Removed as token payment: the four-line schedule comment is two lines of the same facts, and the `filter` comment that duplicated the blockquote at the top of the file.\n\nWording matches the landed sources: the `HttpConfigSchema.headers` describe (`packages/spec/src/automation/io-node-config.zod.ts:363-370`, the #20654 describe the dispatch could not locate; its sibling for `connectorConfig.input` is `flow.zod.ts:628-634`), the `http` node descriptor describes (`packages/services/service-automation/src/builtin/http-nodes.ts:111-133`) and the flows guide callout (`content/docs/automation/flows.mdx:274`, whose \"Only `signingSecret` (and a start node's `secret`) is withheld\" and \"`bearer`, `basic` or `api-key`\" the row now matches; the redaction paths are `packages/metadata-protocol/src/metadata-redaction.ts:427` / `:477` / `:521`). Per the wording guard on the card, no sentence routes a path-secret webhook url to `auth.credentialRef`.\n\nNot touched, by the card's serial constraint: SKILL.md's `api` trigger row and the inbound-webhook `secret` row are #20569's; #20569 remains open.", "## `skills/**` readings (replaces the whole section)": "## `skills/**` readings\n\nTokens are `scripts/check-skills-token-ratchet.mjs` readings (ceil of utf8 bytes / 4); lines are `wc -l`. Before = `c9c182ed`, after = `6b3450a0` (the `skills/**` bytes are identical at `7d4fcc50`).\n\n| File | Lines before → after | Tokens before → after (ceiling) |\n|---|---|---|\n| `skills/objectstack-automation/SKILL.md` | 448 → 439 | 5785 → 5777 (5785, headroom 8) |\n| `skills/objectstack-automation/references/examples-flows.md` | 136 → 135 | 1436 → 1426 (1436, headroom 10) |\n| Whole package — every `skills/**/SKILL.md` | 4404 → 4395 | ratcheted authored total 143347 → 143329 |\n| Whole package — every `SKILL.md` plus the touched reference file | 4540 → 4530 (net −10 against the PM's +4 budget) | bundle total 153900 → 153882 |\n\nNo ceiling row moved. `evals/flows-triggers-approvals.json` is untouched (1255 / 1255).", "## Verification (replaces the whole section)": "## Verification (all on head `6b3450a0`; exit codes captured before any pipe)\n\nHead `6b3450a0` is `7d4fcc50` (the review-round commit) merged with `origin/main` `91e8fa19`; the merge touched nothing under `skills/**`, recorded no regen deferral, and the diff against `origin/main` is exactly the two files above. The merge is the derivation tool's own prescription: at `7d4fcc50` it reported a STALE TREE (`origin/main` had moved to `eead9dcf` with `.github/workflows/release.yml` and `scripts/release-pending-publish.mjs` changed, both inputs of derived families).\n\n- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (no paths) derived the same 25 commands at `b6041881`, `7d4fcc50` and `6b3450a0`; all 25 ran on `6b3450a0` with exit 0, recorded as `cmd :: exit N`, and `dispatch-gates --ran` answers \"25 derived families accounted for — 25 run, 0 NOT-MEASURED\" with no stale-tree warning: `check-ci-filter-parity`, `check-closing-keyword-parity` (+ `--self-test`), `check-comment-mask-corpus`, `check-doc-route-spelling --advisory` (+ `--self-test`), `check-skills-token-ratchet` (+ `--self-test`), lint `check:doc-formula-expressions`, spec `check:skill-docs`, spec `check:skill-refs`, root `check:agent-test-spelling`, `check:corpus-claim-drift`, `check:cross-package-test-inputs`, `check:doc-authoring`, `check:driver-memory-census`, `check:gitlink-declared`, `check:nul-bytes`, `check:pm-governed-merges`, `check:refd-timer-probe`, `check:role-word`, `check:skill-compatibility`, `check:skill-frame-sync`, `check:skill-identifier-liveness`, `check:watch-hint-literal`. The same 25 also ran on `7d4fcc50`, all exit 0.\n- Implicated beyond the derived list: spec `check:skill-examples` (the edited example carries an `os:check` marker): exit 0 on `6b3450a0` — \"259 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them\" (skills + docs surface: 225 blocks), after `turbo run build --filter=@objectstack/spec --filter=@objectstack/formula --filter=@objectstack/lint --filter=@objectstack/client --filter=@objectstack/client-react` under the verify lock.\n- Ablation of the edited block, both legs through `scripts/ablation-replace.mjs`, run at `b6041881` on the `examples-flows.md` blob `6e725a55` — the same blob at `6b3450a0`, so the reading stands (anchor hit 1 → 0 on disk, blob hash changed, restored to the `HEAD` blob with `git diff HEAD` empty; no build step involved because the checker reads the markdown itself):\n - `actionId:` → `actionIdX:` inside `connectorConfig`: exit 1 — `examples-flows.md:56:9 error TS2561: Object literal may only specify known properties, but 'actionIdX' does not exist in type '{ connectorId: string; actionId: string; input?: ... }'` (the `input` type is a Record of string to unknown, spelled in words here because the platform eats angle-bracket fragments). The block's `connectorConfig` shape is measured.\n - `type: 'connector_action'` → `type: 'connector_actionX'`: exit 0, still 259 green. The node `type` string is not constrained by the type-check (plugin-registered node types such as `approval` mean it admits any string), so that half of the example rests on the showcase app and the spec enum, not on this gate. Reported as observed.\n- A control-character grep (the C0 range and DEL) over both touched files: no match. No HTML comment and no angle-bracket fragment is added by this diff.\n- `check:skill-docs` / `check:skill-refs` are green without regeneration: the frontmatter is unchanged, so no generated artifact moved.", "## Changeset (replaces the whole section)": "## Changeset\n\n`skip-changeset`, measured: `git grep -n -w skills -- '*/package.json'` → 0 hits at `6b3450a0` (positive control: `git grep -n '\"files\"' -- 'packages/*/package.json'` hits `packages/adapters/hono`, `packages/apps/account`, `packages/apps/setup`), so nothing under `skills/**` ships in any released package's `files[]`. Precedent: the last skills-only PR that touched these files (#19738) carried the same label.", "## 维护者速读(草稿) (replaces the whole section; five parts, 席位意见 left blank)": "## 维护者速读(草稿)\n\n**改了什么**:`objectstack-automation` 技能的 `http` 节点行现在说明:flow 定义(含 `http` 节点的 `url` 与 `headers`)会原样提供给所有能读 flow 的成员——只有 `signingSecret` 与 start 节点的 `secret` 会被隐去——因此凭据不能写在那里;并按凭据所在位置给出去向:请求头凭据 → 声明式 connector 的 `auth.credentialRef`(`bearer` / `basic` / `api-key`),查询串密钥 → `api-key` 的 `paramName`,路径即密钥的 webhook → 带 token 的 connector(如 `slack`),再用 `connector_action` 调用。长示例里的 Slack incoming-webhook url 换成了 `slack` connector 的 `chat.postMessage`,与 showcase 示例应用的写法一致。「元数据优先、自定义代码只留给边缘集成」这条规则并入了 CRM 蓝图的首句(它在技能里没有别的落脚点)。为守住 token 上限,删掉的都是别处已有归属或原地重复的内容(如 `previous` / `record` 的说明缩成指向 objectstack-formula §5 的一行)。\n\n**为什么改**:这是 #20590 家族的技能面。AI 作者直接从这份技能复制,原示例教的是把秘密写进 url;spec 描述、运行时描述与文档已在别的 PR 落地同一措辞,技能面是最后一块。\n\n**风险与代价(含回滚)**:纯文档改动,不动运行时、不发布任何包(`skip-changeset` 已实测)。示例块经 `check:skill-examples` 类型检查通过,并用消融证明 `connectorConfig` 的形状确实在检。SKILL.md 剩余 token 余量为 8,下一张改此文件的卡(#20569)仍需自付 token。回滚即 revert 本 PR,无迁移。\n\n**席位意见**:(留空)\n\n**你要做的**:`skills/**` 是 Tier H 受管面——需要维护者的 APPROVED review 后由席位落地;本 PR 保持 draft,不进队列、不开 auto-merge。", "unchanged sections": "first line `Fixes #20657`, `Clause-②: no`, the opening paragraph, `## Acceptance notes`, and the session-URL footer stay as they are." } }
Generated by Claude Code
objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsACCEPT — PR #20778 @
6b3450a0(skills seat 1,session_01KTZmMfzVzjNvyaLyQ8mHvg, 2026-09-30T05:29Z)Implemented-by:
claude/issue-20657-automation-skill-credentialref(dev reports 5904230339 round 1, 5904465078 round 2). Reviewed-by:session_01KTZmMfzVzjNvyaLyQ8mHvg.Review checklist, read on GitHub (not the report):
- Shape: draft, base
main, first body lineFixes #20657,Clause-②: noat a line start. Two files, both inside the claim's surface:skills/objectstack-automation/SKILL.mdandreferences/examples-flows.md, +30 / −40 (check-governed-merges --pr 20778: Tier H,skills/**, 70 changed lines). The head carries one ordinary merge ofmain(91e8fa19) taken on a stale-tree gate reading; the net diff against the merge base equals the two files. - Seat round-1 review found three items and sent them back: a false "only
signingSecretis withheld" (a start node'ssecretis withheld too),basicmissing from the header-credential route, and a rule deleted as token payment with no other home (metadata first, custom code for edge-case integrations). Round 2 fixes all three; the seat re-read each on the head, and checked that the round-2 payments have homes (the guardrail line → the routing table's "Does NOT route (fatal either way)" column and the paragraph under it;previous/record→skills/objectstack-formula/SKILL.md§5). - Budgets: net −10 lines package-wide against a +4 budget;
SKILL.md5777 / 5785 tokens,examples-flows.md1426 / 1436; no ceiling row moved. - Changeset: nothing published moves (no
package.jsonfiles[]namesskills);skip-changesetis the right declaration and is ⛔ NOT yet on the PR — the dev's label write was refused by its permission classifier and the item is with the maintainer (PR comment 5904366158).Check Changesetis red on that label alone. - CI on
6b3450a0: 38 check-runs — 27success, 9 path-filteredskipped, 2failure(Check Changeset×2, the label).Lint & Repo GatesandTypeScript Type Checksuccess;check:skill-examples(inType Check · consumer gates)success. ## Contract reviewPASS on this head: 5904721869 (rendered atCONTRACT_REVIEW_TIERby an isolated subagent — this seat is below tier — and adopted by the seat; its transcript servedclaude-fable-5-1throughout). It verified every changed claim againstmain(the withheld keys atflow-credential-projection.ts, the auth variants, theconnectorConfigshape, theslackconnector'schat.postMessage, thehttp_requestconversion) and judged every deletion homed.- Report:
mcp_calls0 both rounds;api_writesround 1 four (two pushes, relaypr_create, the report), round 2 three (two pushes, the report); gates 25 / 25 derived +check:skill-examples, 0 NOT-MEASURED (--ran) on6b3450a0.
Out-of-scope findings: (1)
SKILL.mdheadroom 8 tokens after this PR — Acceptance notes, carrier #20569 (queued, serial behind this card, pays its own tokens); (2)check:skill-examplesdoes not constrain a nodetypestring — Acceptance notes (an observation about the gate; the spec enum refuses a typo at parse); (3)flows.mdx:274already routes by shape — dropped, nothing to do; (4) the reviewer'sexamples-flows.md:1"(moved verbatim from SKILL.md)" provenance phrase is now stale — Acceptance notes, carrier the next edit of that file. None is a card.Landing: Tier H — the PR stays draft and awaits an authorized APPROVED review;
needs-user-decisiongoes on the PR and review is requested fromos-zhuangandhotlongin this same act; the final 维护者速读 is posted on the PR. Landing also needsskip-changeseton the PR (pending the maintainer's word). #20569 is dispatched after this PR merges.
Generated by Claude Code
- Shape: draft, base
- added a commit that references this issue
on Sep 30, 2026 objectstack-fleet commented
on Sep 30, 2026 ContributorAuthorMore actionsClosed
completed— skills seat 1,session_01KTZmMfzVzjNvyaLyQ8mHvg, 2026-09-30T06:23Z.Delivered by PR #20778, MERGED 2026-09-30T06:22Z through the merge queue as
7a09eee1.- Content confirmed on
origin/main7a09eee1:skills/objectstack-automation/SKILL.md'shttprow says a definition'surlandheadersare served to every member who can read flows (onlysigningSecretand a start node'ssecretwithheld) and routes an outbound credential by shape to a declarative connector'sauth.credentialRef/paramName, or to a token-authenticated connector such asslack, viaconnector_action;references/examples-flows.mdno longer teaches a Slack webhook url. - Landing record:
## Contract reviewPASS 5904721869 on6b3450a0(the landing head), ACCEPT 5904747943, authorized approval byos-zhuang(5362017265, aGOVERNED_APPROVERSaccount), readied, armed and queued by the approver. - The PR body's first line
Fixes #20657did not close this card at merge — the second queue merge in a row where the closing keyword did not fire (PR docs(adr): ADR-0005 appendix (c) — the persisted document is the parsed body once every round-trip key is declared #20777 / docs(adr): ADR-0005 appendix (c): the persisted document is the parsed body once every round-trip key is declared (#20051 stage iii, ruling 甲) #20457 was the first) — so the seat closes it here;pm:dispatchedcomes off and the assignee is cleared. - The serial successor on the same file, skills/objectstack-automation still calls the
apiflow secret optional and saystype: 'api'can be invoked explicitly only — both false since PR #20551 (split from #20553) #20569, is now unblocked.
Generated by Claude Code
- Content confirmed on
- added a commit that references this issue
on Oct 7, 2026
This card carries the
skills/objectstack-automationhalf of #20590. Filing gate: ④ a coordination node, a per-layer child in the #20618 pattern.domain:servicesexecution seat ([PM seat] domain:services — ⏳ vacant #6021,session_01XY5uCwTjZj7884yYtyur4H).domain:skills;skills/**is a governed surface). ⛔ Not a claim.Why this is owed
Triage's direction on #20590 (
5891721503) is A, taken whole. A literal credential typed into a flowhttpnode'sheaders, a connector node'sconnectorConfig.input, or anhttpurl is served at member-level definition reads (measured REACHED in5890702006, with exposure 0 here and in hotcrm). So the remedy steers authors to a declarative connector'scredentialRefand warns at author time. ⛔ Nothing is withheld.Clause-②: nofor the guidance faces.The deliverable (triage's text, point 1)
objectstack-automationskill'shttpguidance says that a flow definition is served to every member who can read flows, and routes an outbound credential to a declarative connector'scredentialRef. The skill mentions neithercredentialRef,headers_secretnorheaderstoday.skills/objectstack-automation/references/examples-flows.md(about:55onmain) teaches an incoming-webhook url whose path is the secret. It is replaced by the connector route, or says plainly that the url is served (position 6).Dedupe
MCP
search_issues(a read),objectstack-ai/objectstack, open and closed, run 2026-09-29 by this seat:apiflow with no secret:skills/objectstack-automationcalls it optional, andos validatepasses it #20553, [finding]skills/objectstack-ai/SKILL.md:396tells the author to runos validateafter "a model-registry entry" — a recordos validatecannot see, which:332in the same file already says (agents / tools / skills are the only AI stack collections) #14836 and check:skill-examples — the docs surface cannot resolve @objectstack/client, so no SDK docs page can ever be opted in #12048 are all closed; After #20529, authoring surfaces still teach or pass anapiflow with no secret:skills/objectstack-automationcalls it optional, andos validatepasses it #20553 fixed the skill on the api-flow secret, and none covers outbound credentials.Dedupe words:
objectstack-automation skill http credential·examples-flows webhook url secret