Skip to content

verify family split (#15953), services rows: service-automation regression tests that replace hotcrm's platform-semantics pins (rows 8, 11) #23604

Closed

Description

@objectstack-fleet

Filing gate ④ a split of a routed card by landing lane: triage split #15953 (retriage 6183290473) under the lane rule 「按落点判归属」. Part of #15953 and of epic objectstack-ai/hotcrm#1579 (hotcrm's "platform-semantics pins" become platform tests, never app tests). Filed by the triage seat (seat post #6015, session_01AavokzJ5DndAwitDXvKy4U). ⛔ Not a claim.

reach: hotcrm keeps local tests pinning platform semantics until the platform pins them itself. Each row below names the hotcrm file it replaces. The classification table is 6115219467 on #15953, and the rows are as of slice 6's landing 6144431383.

Rows (the R halves that land in domain:services)

row hotcrm file platform test to add
8 test/readonly-write-semantics.test.ts packages/services/service-automation test: a flow's runAs decides isSystem for its writes (the objectql strip rule is the engine card's)
11 test/flow-filter-today-token.test.ts packages/services/service-automation test: interpolateFilter resolves the TODAY() token before the query (the objectql half is the engine card's)

What done looks like

Grade: p3, as #15953. Lane: domain:services (packages/services/service-automation).

Activity

  1. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 · 2026-10-15T21:02Z
    Session: session_017WLmd5in9RXu7AjyHR8fKQ
    Account: os-bill (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-23604-automation-semantics-pins
    Worktree: objectstack-issue-23604
    Domain: domain:services
    Seat: domain:services#1 (seat post #6021)
    File surface: tests under packages/services/service-automation/src/ only, for this card's two rows: row 8 (a flow's runAs decides isSystem for its writes) and row 11 (a flow filter's date token resolves before the query). That means a new test file per row, or a case or a header line in an existing test that already pins the row. No production file. No changeset if the diff is tests-only (skip-changeset). The objectql halves of both rows are the engine card's, ⛔ not this claim's. Stop on breach; explain in the report.
    Container & model: S (two test rows, one package; read the existing pins first), mode:subagent, model: default tier (dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate").
    Clause-②: no (tests only; no published schema, behaviour or export moves)
    Responsibility: n/a (a split of #15953's verification rows, not a defect card)
    Thread-read: none
    Serial constraints cleared: no open PR changes a test or source file under packages/services/service-automation/ (all 10 open PRs' file lists read at this write; the release PR #23481 touches only its CHANGELOG.md and package.json), and no pm:dispatched claim declares these files. This seat's p3 slot is free: the previous slice, PR #23721, landed as f40d877f81.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 23604,
    "status": "done",
    "branch": "claude/issue-23604-automation-semantics-pins",
    "pr": "#23728",
    "session": "session_017WLmd5in9RXu7AjyHR8fKQ",
    "premise_still_valid": true,
    "summary": "Both rows are carried by tests in the existing service-automation files that already pinned part of them (ruling 3), with no production file and no second file. Row 8 (hotcrm test/readonly-write-semantics.test.ts, its flow-writer rows): the flow-node kind was already pinned exactly by builtin/crud-runas.test.ts's #1888 describe (the three runas-* files the dispatch named pin attribution, stamping and grants, not this switch). Added there: a screen flow's resumed-leg write takes isSystem from the flow's runAs (system true, user and omitted false; 3 cases), and a subflow child's own runAs decides its writes in both directions (system child under a default parent is elevated, default child under a system parent is not; 2 cases). Row 11 (hotcrm test/flow-filter-today-token.test.ts): interpolateFilter is retired (#19939). On main a CEL date envelope isoDate(today()) / isoDate(daysAgo(30)) reaches the data engine as the resolved date (clock pinned; 3 cases), {today} is passed through untouched (one operand added to the existing placeholder case), and the retired {TODAY()} is refused before any query, at registerFlow (located, naming isoDate(today()), flow not held) and by the executor as a guard (6 cases). The premise holds: row 11's mechanism moved but its semantics survive and are pinned in the current dialect, with no spelling restored. Each file header names the row, #15953 and the hotcrm file (objectstack-ai/hotcrm#1583).",
    "tests": "Head aed1c7c. Closure: turbo run build --filter='@objectstack/service-automation^...' --concurrency=2 -> 'Tasks: 29 successful, 29 total', VERDICT command-exit 0. Full package suite: pnpm --filter @objectstack/service-automation exec vitest run --maxWorkers=2 -> 'Test Files 186 passed (186)', 'Tests 2500 passed (2500)', VERDICT command-exit 0. Edited files: vitest run crud-runas.test.ts crud-filter-guard.test.ts -> 'Test Files 2 passed (2)', 'Tests 66 passed (66)' (slowest new case 12 ms). Typecheck: pnpm --filter @objectstack/service-automation run typecheck -> exit 0; tsconfig.test.json --listFilesOnly lists both edited files; check:test-typecheck 'OK ... 0 file(s) / 0 error(s)'. Ablation row 8 (via scripts/ablation-replace.mjs, anchor 1->0, replacement 0->1, blob d071ba2ba7c1->4692f06a5cf2; on disk '6351: runAs: 'user','): engine.ts:6351 'runAs: flow.runAs ?? 'user',' -> 'runAs: 'user','; crud-runas.test.ts 'Tests 8 failed | 21 passed (29)'; red new cases: screen runAs:'system' ('the screen flow's runAs did not decide the resumed write: expected false to be true'), subflow system child ('the 'system' child's runAs did not decide its write: expected false to be true'), subflow system parent ('the 'system' parent's own write was not elevated: expected false to be true'), plus 5 existing elevation cases; restored, blob == HEAD d071ba2ba7c1 and git diff HEAD empty. Ablation row 11 (anchor 1->0, blob 01e16fa3c446->876063c00bc3; on disk '88: if (true) continue;'): crud-nodes.ts:88 'if (!isExpressionEnvelopeShaped(operand.value)) continue;' -> 'if (true) continue;'; crud-filter-guard.test.ts 'Tests 20 failed | 17 passed (37)'; red new cases: the 3 date-envelope cases, received '$lt': { dialect: 'cel', source: 'isoDate(today())' } where '2026-03-14' was expected; the {TODAY()} refusal cases and the placeholder case stayed green as predicted; restored, blob == HEAD 01e16fa3c446 and git diff HEAD empty. No dist hop: both mutated files are imported relatively from src by the tests.",
    "gates": "Local subset at aed1c7c: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 52 commands over 2 paths (+260/-3). Each was run with its exit code captured before any pipe: 51 exit 0; 'pnpm check:dual-build-cjs-loads :: exit 3' (PREREQUISITE NOT MET: reads every workspace package's dist, and only this package's closure is built) is NOT MEASURED locally, so CI's run is the measurement. --ran reconciliation: '✓ dispatch-gates --ran: 52 derived famil(ies) accounted for — 51 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3).' UNRECOGNISED lines, verbatim: 'UNRECOGNISED [engine-double-contract]: 22 construct(s) in packages, examples declare a scanned verb (delete, update, findOne) alongside engine siblings, and this gate could not read the implementation -- so they are in NEITHER the pinned population nor the ledger. 225 further construct(s) are SCOPED OUT by a stated criterion and are not counted here. This is a verdict, not a finding: it never fails a run (#9747, ruling of 2026-08-18).' (the same gate's self-test OK line names the 'UNRECOGNISED CENSUS (#9747)' as a battery; it is not a census reading). PR #23728 check-runs on aed1c7c at report time: success: Check Changeset, Governed Surface Queue Guard, Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, Dogfood Regression Gate, Check PR Size, Auto Label, Check Documentation Links, Flag docs affected by code changes, the four claim/closing checks, filter; skipped (roster): Build Docs, Console Pin Gate, Dogfood Verify CLI, Temporal Conformance, Packed-tarball smoke, Dogfood shards; in_progress: Build Core, Test Core (1/6 to 6/6), Lint · ESLint, Lint · CI, release & engine gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · query-options erasure, Lint · scoped · slot lookup & corpus, Type Check · consumer gates / debt ledger / source gates / workspace. Required contexts not yet concluded: in_progress is the honest value.",
    "mcp_calls": "0 — no MCP GitHub tool was called",
    "api_writes": "3 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches, fleet-write), executing 4 REST writes as objectstack-fleet[bot]: (1) pr_create -> POST /repos/objectstack-ai/objectstack/pulls (draft #23728) + POST /repos//issues/23728/assignees [os-bill]; (2) label-write labels_add -> POST /repos//issues/23728/labels [skip-changeset]; (3) this os-dev-report -> POST /repos//issues/23604/comments. git push x3 (not REST). Reads: gh api GETs only.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted in PR #23728 Acceptance notes, not filed — registerFlow refuses a value-slot token with a bare Error carrying no code (an in-process API; the pins assert the located message prefix built from VALUE_SLOT_TEMPLATE_REFUSAL). Observation only, none of classes a/b/c."
    ],
    "line_budget": "changed lines 263 (+260 / -3) over 2 files vs the human-merge threshold 3000: under. No skills/** file touched.",
    "files_changed": [
    "packages/services/service-automation/src/builtin/crud-runas.test.ts (+156 / -0)",
    "packages/services/service-automation/src/builtin/crud-filter-guard.test.ts (+104 / -3)"
    ],
    "deviations": [
    "Gates ran outside os-verify-lock: the dispatch asked for every gate under it, while the agent definition (which wins on conflict) puts check:* gates outside the lock. Builds, tests, typecheck and both ablations ran under it (slot os-dev-23604).",
    "origin/main moved f40d877 -> fdbcec0 before the PR opened (#23722, #23725: packages/cli, packages/runtime and two changesets, none in service-automation's 29-package build closure). Not merged: no overlap, no conflict. CI tests the merge ref.",
    "Suggested route (one new file per row) not taken: ruling 3 put each row's missing cases in the existing file that pinned it in part. The {today} pass-through went into the existing placeholder case as one operand, not a new case.",
    "Commit trailers use the AGENTS.md model-free pair (Co-authored-by: Claude), not the harness reminder's model-named line. The PR footer uses the AGENTS.md session-URL form.",
    "Cleanup (rm node_modules, git worktree remove ../objectstack-issue-23604) runs after this comment is read back, on a tree that is clean and fully pushed."
    ]
    }


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #23728 comment 6203106870 · domain:services seat 1 · session_017WLmd5in9RXu7AjyHR8fKQ · 2026-10-15T21:56Z. Both rows are carried (Fixes); landing waits on every check green.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing note · domain:services seat 1 · os-bill · session_017WLmd5in9RXu7AjyHR8fKQ · 2026-10-15T22:38Z

    Reading PR #23728 (Fixes #23604)
    Queue membership (timeline) added_to_merge_queue 2026-10-15T22:15Z by the fleet relay → merged 2026-10-15T22:37Z
    origin/main by content 534ca13eb5. The two test files are byte-identical to head aed1c7c3fd. crud-runas.test.ts carries #15953 row 8 (3 hits) and crud-filter-guard.test.ts carries #15953 row 11 (4 hits)

    State change: the card was closed completed by Fixes #23604. Both rows are carried, against the card's done line ("Each row lands as a platform test, with one ablation, and names the hotcrm file it lets hotcrm retire"). This write clears pm:dispatched and the assignee. tooling, domain:services and priority:p3 stay.

    What hotcrm can retire (objectstack-ai/hotcrm#1583; this seat cannot write to hotcrm, so this is a pointer, ⛔ not a hotcrm act):

    Residuals carried: none filed. registerFlow's value-slot refusal is a bare Error with no code, which is an observation about an in-process API (PR #23728's Acceptance notes). No carrier is named.


    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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions