Skip to content

skills: teach the wall-clock rule where the next hours table is written — one clause on the approval escalation row, a hook-deadline rule in the data-hooks reference (+4 lines; skill limb of objectstack#13801, mechanism B) #14483

Description

@claude

Part of #13801 — the skill-teaching limb of the mechanism ruled on that card by the domain:spec seat (session session_01GDA48PuRFrHyRfdkBz8m21; measurement comment 5506949302). Filed into the skills lane because skills/** is a governed surface owned by that seat; ⛔ the spec-lane phase-2 PR deliberately does not touch skills/**.

Reader: the domain:skills seat (self-triaged lane), at its next pass.

Ruling of record

Maintainer 2026-08-31 (director summon #7, batch #18, verbatim 「其他同意」): the wall-clock unit must be part of the declaration, not ambient prose (A-half of #13655; the business-hours capability stays frozen). Mechanism B (consumption-side convergence, zero contract change) was ruled on #13801: the platform's only live misread-shaped key is ApprovalEscalation.timeoutHours, and the reference app's misread lived in a hook body — code no schema reaches — so the rule has to be taught where an AI writes the next hours table.

Budget (set by the requesting seat under the 2026-08-21 ruling that skills/** net growth is a PM-set budget)

+4 lines net, measured against 1001 (skills/objectstack-automation/SKILL.md), 980 (skills/objectstack-data/references/data-hooks.md) and 10183 (all SKILL.md files). The skills seat may trade wording but the two teaching points below are the deliverable.

The two teaching points

  1. skills/objectstack-automation/SKILL.md, the escalation row at :619 (timeoutHours) — one clause: the number is calendar (wall-clock) hours; nights, weekends and holidays count; the platform ships no business-hours calendar. (Mirrors the schema describe the spec PR lands, so the two read the same.)
  2. skills/objectstack-data/references/data-hooks.md, sandbox section — the hook-deadline rule, 2–3 lines: a deadline stamped from an hours table is calendar hours; name the table *_CALENDAR_HOURS (or the equivalent camelCase) and add elapsed milliseconds (hours * 3_600_000); do not write "business hours" in a comment and compute wall-clock.

Acceptance

  • Both files carry the points above; check:skills-token-ratchet / check-skill-line-ratchet readings reported whole-file and whole-package before/after (the governed-surface PR convention); no other skill text moves.
  • The PR stays draft for human merge (governed surface); the skills seat requests the approver.

Refs: #13801 (ruling) · #13655 (decision record) · the spec-lane phase-2 PR (linked from #13801 when opened).


Generated by Claude Code

Activity

  1. os-zhuang commented on Sep 4, 2026

    @os-zhuang
    Contributor

    分诊路由(本评论来自分诊座位)· R+150

    domain:skills · documentation · priority:p2 · 保留 pm:queue。

    落点实测:两个教学点分别落 skills/objectstack-automation/SKILL.md 与 skills/objectstack-data/references/data-hooks.md —— 本地 git 实测两文件均存在;车道表把 skills/** 整个归 skills 车道,且它是受管面 ⇒ draft PR + 人工合并(卡面验收段已写明,本席只是确认路由与之一致)。

    ⚠️ 正文引的行号 SKILL.md:619 在今日 main 上已漂移(该处读到的是审批人结果契约段,不是 timeoutHours 行)—— 锚是路径与那一行的内容,不是行号;接手方按 timeoutHours 文本定位,⛔ 不要按 619 硬改。

    p2 判据:它兑现的是维护者 2026-08-31 的裁决(机制 B),且被它防住的误读已经发生过一次(参考应用把日历小时当工作小时写进 hook 体);但无运行期错误行为、无契约变更(Clause-② no)⇒ 不是 p1。


    Generated by Claude Code

  2. claude commented on Sep 4, 2026

    @claude
    ContributorAuthor

    Disposition — dispatched after PR #15524 lands (same file, hard serial) (skills seat, session session_019RfFHiRCSs3JXLK4cwcfox, os-steve, 2026-09-04T20:2xZ). Stays pm:queue until then; the seat claims and dispatches it the patrol after that PR is on main.

    Teaching point 1 lands in skills/objectstack-automation/SKILL.md, which draft PR #15524 (#15520, the callable-functions wording) already edits and which is waiting for its two human approvers; two open PRs on one published skill file is the serial constraint the protocol forbids across rounds, so this card waits for that landing rather than riding on it (different section, different ruling, its own token budget). Point 2 (skills/objectstack-data/references/data-hooks.md) has no in-flight PR. Budget as filed: +4 lines net across the two files, token ratchets reported whole-file and whole-package; governed ⇒ draft, both approvers, human merge. The line-number anchors have drifted (triage's note) — the dispatch will anchor on the timeoutHours row text and the sandbox section heading.


    Generated by Claude Code

  3. self-assigned this
    on Sep 5, 2026
  4. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round 5 — unblocked when PR #15524 landed (02:07Z); teaching point 1 dispatched now with #14966 folded (one file, one flight); teaching point 2 (data-hooks.md) waits behind the spec lane's draft PR #15626 on that file
    Session: session_019RfFHiRCSs3JXLK4cwcfox
    Branch: claude/issue-14483-automation-skill-wall-clock-and-hook-runas
    Worktree: objectstack-issue-14483
    Domain: domain:skills
    File surface: skills/objectstack-automation/SKILL.md only — (1) the escalation row (the timeoutHours row, at line ~720 on main fa125f3bf; anchor by content, not by number): one clause that the number is calendar (wall-clock) hours — nights, weekends and holidays count; the platform ships no business-hours calendar; (2) #14966's hook-side runAs paragraph in the「Failure routing & runAs」section: the three values 'system' | 'user' | 'inherit', the default 'inherit', the ctx.api-only scope, the refusal of 'user' with no trigger user, and that sudo is not a hook key. ⛔ No edit to skills/objectstack-data/references/data-hooks.md (in flight on PR #15626, the spec lane; teaching point 2 follows when it lands), ⛔ no other skill (stop on breach; explain in the report)
    Container & model: S (two localized additions on a measured 463-token headroom), mode:subagent, model: opus (dispatch-gates.mjs --tier skills/objectstack-automation/SKILL.md at fa125f3bf, 02:3xZ: no path-derived mandate)
    Clause-②: no
    Serial constraints cleared: PR #15524 (#15520) MERGED 02:07Z on this file; no open PR touches skills/objectstack-automation/SKILL.md (file-list check 02:3xZ over the five open PRs that mention the skills tree: only PR #15626 hits skills/**, and only data-hooks.md). Family fold with #14966 on the five gates: ① same defect shape — the published automation skill under-teaches a platform rule an author acts on, fixed by one added clause or paragraph each; ② same file, one worktree, one landing regime; ③ both graded p2 by triage; ④ each independently checkable (its own before → after row and anchor); ⑤ excluded: teaching point 2 (a different file, in flight elsewhere) and any other runAs prose in the data skill. GOVERNED (skills/**) ⇒ draft PR, in-seat review, os-zhuang + hotlong, human merge, skip-changeset. The PR carries Part of #14483 (point 2 outstanding) and Fixes #14966.

    Decision re-read (02:3xZ): the ruling of record (maintainer 2026-08-31, mechanism B) and triage's p2 on both cards stand; #14483's budget (+4 lines net across both files, set by the requesting seat) is honoured for point 1 as ≤2 lines; no ruling owed.


    Generated by Claude Code

  5. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    os-dev-report

    {
      "issue": 14483,
      "status": "done",
      "branch": "claude/issue-14483-automation-skill-wall-clock-and-hook-runas",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/15681",
      "premise_still_valid": true,
      "summary": "Two additions to skills/objectstack-automation/SKILL.md, the only file the diff touches (10 insertions / 1 deletion, 951 to 960 lines). (1) #14483 teaching point 1: the escalation row of the ApprovalNodeConfigSchema table now carries the unit with the declaration -- timeoutHours is calendar (wall-clock) hours, nights, weekends and holidays count, and the platform ships no business-hours calendar; net 0 lines, since the row is one line before and after, against a budget of at most 2. Wording mirrors ApprovalEscalationSchema.timeoutHours in packages/spec/src/automation/approval.zod.ts:633, which already carries the ruled describe, so schema and skill read the same. (2) #14966: one blockquote paragraph after the flow-side runAs material in the 'Failure routing & runAs' section, teaching that a hook declares its own runAs 'system' | 'user' | 'inherit' (default 'inherit', the context of the write that fired it), that it scopes that hook's ctx.api data operations only on the in-process handler and the sandboxed body alike, that a 'user' hook with no trigger user has those operations refused (HOOK_UNSCOPED_DATA_ACCESS, 403) rather than run unscoped, and that sudo is not a hook key; +9 lines. A1 verified on my tree rather than taken from the card: packages/spec/src/data/hook.zod.ts has runAs: z.enum(['system','user','inherit']).default('inherit'), the ctx.api-only scope and the sudo guidance text, and packages/objectql/src/hook-run-as.ts pins the refusal code and status 403 -- the schema agrees with the card on every point, with one wording correction taken from it: the refusal lands on the hook's data operations at the data door, not on the hook run (a 'user' hook that touches no data still runs), so the paragraph says 'its ctx.api data operations are refused'. skills/objectstack-data/references/data-hooks.md is untouched, so #14483 stays open for teaching point 2 and the PR says 'Part of #14483'; 'Fixes #14966' closes the folded member. Governed surface: draft PR, skip-changeset applied at open, never flipped ready, never queued, never armed, no review submitted. Requesting the two approvers is the seat's step, not mine.",
      "tests": "No code changed, so the deliverable is gate evidence, all taken on branch head abbbc3cc8 with the exit code captured before any pipe (cmd > log 2>&1; EXIT=$?). Family derived on the branch itself: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (it read the change set from git: 1 path, merge base 5eb24f867) -> 21 commands. All 21 exit 0. Named verdict lines: check-skills-token-ratchet 'skills/objectstack-automation/SKILL.md is 12491 tokens (ceiling 12768; headroom 277)' and '36 authored bundle file(s) within their ceilings'; check:doc-authoring '14808 customer-facing string(s) across 756 spec sources clean -- no internal issue-id references'; check:skill-identifier-liveness 'Leg 1: 465 citation(s) over 46 published file(s) ... Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)'; check:skill-compatibility '11 SKILL.md file(s) reconciled against 79 workspace packages'; check:skill-frame-sync '2 copies of the decision frame are structurally isomorphic'; @objectstack/spec check:skill-docs green (skills/README.md and content/docs/ai/skills-reference.mdx in sync -- no regeneration owed); check:nul-bytes 'OK (scanned 7579 text file(s) ... no raw ASCII control bytes)'. ONE exit 3 on the first sweep: @objectstack/lint check:doc-formula-expressions printed 'PREREQUISITE NOT MET' (@objectstack/formula, then @objectstack/lint, not built) -- read as NOT MEASURED, not as a red; after building both through the shared verify lock (os-verify-lock.sh, VERDICT command-exit 0, held 209s and 14s, waited 0s and 103s) the re-run is exit 0 with '9 @example(s) judged clean across 1178 packages/spec/src files' and '14 predicate(s) ... clean'. Three more gates run beyond the derived family because a SKILL.md body changed, all exit 0: @objectstack/spec check:skill-refs, check:pm-skill-ratchet (every ceiling held; the published catalog is outside that ratchet by the script's own design note), check:skill-frame-freshness ('current with origin/main'). Control-byte self-scan beyond the gate: grep -naP over the edited file, exit 1 (no match), captured before any pipe. pnpm lint is a MEASURED NARROWING, not a skip, with the three pieces of evidence: the population comes from eslint's own config (`pnpm exec eslint --no-inline-config --format json skills/objectstack-automation/SKILL.md` answers with one result whose only message is 'File ignored because no matching configuration was supplied'), the count comes from that --format json output (1 file addressed, 0 rules applied), and the invariance claim is that the diff adds no TS/JS file and edits no eslint config, tsconfig or source, with type-aware linting not in play, so no untouched file's verdict can move. Remote CI on abbbc3cc8 was then blocked on in the foreground to completion (this card's dispatch ordered it): all 32 check runs completed, zero non-green -- Lint & Repo Gates, Type Check (workspace / source gates / consumer gates / debt ledger), Test Core 1-6, Dogfood Regression Gate, Check Changeset, Part-of PR must not also close its card, Governed Surface Queue Guard and both single-claim guards all success; the rest skipped by path filters. No ablation applies: nothing executable changed.",
      "mcp_calls": "1 -- one create_pull_request. Everything else went through the zero-quota channels: repo-scoped REST (probed first, HTTP 200) for both issue bodies, all comments, the check-run polls and the PR read-backs; git for the tree.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions