Skip to content

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

@objectstack-fleet

This card carries the skills/objectstack-automation half of #20590. Filing gate: ④ a coordination node, a per-layer child in the #20618 pattern.

  • Filed by the domain:services execution seat ([PM seat] domain:services — ⏳ vacant #6021, session_01XY5uCwTjZj7884yYtyur4H).
  • ⛔ Filed bare: triage routes it (its lane split names 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 flow http node's headers, a connector node's connectorConfig.input, or an http url is served at member-level definition reads (measured REACHED in 5890702006, with exposure 0 here and in hotcrm). So the remedy steers authors to a declarative connector's credentialRef and warns at author time. ⛔ Nothing is withheld. Clause-②: no for the guidance faces.

The deliverable (triage's text, point 1)

  • The objectstack-automation skill's http guidance says that a flow definition is served to every member who can read flows, and routes an outbound credential to a declarative connector's credentialRef. The skill mentions neither credentialRef, headers_secret nor headers today.
  • skills/objectstack-automation/references/examples-flows.md (about :55 on main) 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).
  • This is the AI-facing surface an author copies from, which is why triage took the guidance half whole.

Dedupe

MCP search_issues (a read), objectstack-ai/objectstack, open and closed, run 2026-09-29 by this seat:

Dedupe words: objectstack-automation skill http credential · examples-flows webhook url secret

Activity

  1. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: route — documentation · priority:p1 · domain:skills · area:access · pm:queue. #20590's skills/objectstack-automation half, carrying its p1

    Triage 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.

  2. added
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    documentationImprovements or additions to documentation
    priority:p1High: required for production / M2
    on Sep 29, 2026
  3. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    A wording guard for this card's skill text · domain:services seat (#6021) · session_01XY5uCwTjZj7884yYtyur4H · 2026-09-29T16:35Z · ⛔ not a claim

    The 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:


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01KTZmMfzVzjNvyaLyQ8mHvg
    Account: os-warren (the seat's linked user as GET /user answers 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 (the http node guidance: the node-table row :88, the reference-outside-a-filter sentence :216 and the Slack-webhook routing sentence :259, plus any other sentence there that tells an author what to write in an http node's url / headers) and skills/objectstack-automation/references/examples-flows.md (the notify_manager http node, url at :55); scripts/check-skills-token-ratchet.mjs only 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.md is 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 touches skills/objectstack-automation/** or content/docs/automation/** (all ten open PRs' file lists read at the round-open marker 5903866929); this lane has no pm:dispatched card, so no in-flight claim of this lane declares these paths.

    Readings at 2026-09-30T04:12Z on origin/main c9c182ed: the skill names neither credentialRef nor headers_secret (git grep -n -i "credential" origin/main -- skills/objectstack-automation → 0 hits; control git grep -n "http" origin/main -- skills/objectstack-automation/SKILL.md → 4 hits, :88 / :116 / :216 / :259); examples-flows.md:55 still carries url: 'https://hooks.slack.com/services/...'. The wording sources the triage names are on main: content/docs/automation/flows.mdx:274 (the landed guide sentence, already routing by shape — header → bearer / basic / api-key with auth.credentialRef, query key → api-key with paramName, path-borne webhook secret → a token-authenticated connector) and the http node describes in packages/services/service-automation/src/builtin/http-nodes.ts:111–:133 (PR #20672, merged). Parent #20590 is closed completed; #20654 and #20655 are closed completed.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    os-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

  6. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    os-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

  7. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — 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 line Fixes #20657, Clause-②: no at a line start. Two files, both inside the claim's surface: skills/objectstack-automation/SKILL.md and references/examples-flows.md, +30 / −40 (check-governed-merges --pr 20778: Tier H, skills/**, 70 changed lines). The head carries one ordinary merge of main (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 signingSecret is withheld" (a start node's secret is withheld too), basic missing 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.md 5777 / 5785 tokens, examples-flows.md 1426 / 1436; no ceiling row moved.
    • Changeset: nothing published moves (no package.json files[] names skills); skip-changeset is 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 Changeset is red on that label alone.
    • CI on 6b3450a0: 38 check-runs — 27 success, 9 path-filtered skipped, 2 failure (Check Changeset ×2, the label). Lint & Repo Gates and TypeScript Type Check success; check:skill-examples (in Type Check · consumer gates) success.
    • ## Contract review PASS on this head: 5904721869 (rendered at CONTRACT_REVIEW_TIER by an isolated subagent — this seat is below tier — and adopted by the seat; its transcript served claude-fable-5-1 throughout). It verified every changed claim against main (the withheld keys at flow-credential-projection.ts, the auth variants, the connectorConfig shape, the slack connector's chat.postMessage, the http_request conversion) and judged every deletion homed.
    • Report: mcp_calls 0 both rounds; api_writes round 1 four (two pushes, relay pr_create, the report), round 2 three (two pushes, the report); gates 25 / 25 derived + check:skill-examples, 0 NOT-MEASURED (--ran) on 6b3450a0.

    Out-of-scope findings: (1) SKILL.md headroom 8 tokens after this PR — Acceptance notes, carrier #20569 (queued, serial behind this card, pays its own tokens); (2) check:skill-examples does not constrain a node type string — Acceptance notes (an observation about the gate; the spec enum refuses a typo at parse); (3) flows.mdx:274 already routes by shape — dropped, nothing to do; (4) the reviewer's examples-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-decision goes on the PR and review is requested from os-zhuang and hotlong in this same act; the final 维护者速读 is posted on the PR. Landing also needs skip-changeset on the PR (pending the maintainer's word). #20569 is dispatched after this PR merges.


    Generated by Claude Code

  8. added a commit that references this issue on Sep 30, 2026
    7a09eee
  9. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Closed 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.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdocumentationImprovements or additions to documentationdomain:skillspriority:p1High: required for production / M2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions