Repository navigation
verify: the in-process handle boots a leaner stack than serve and has no door for eight things an app's tests need (requires[] capabilities, system/predicate update, the form door, user-less triggers, …), measured by hotcrm#2013 #22301
Description
Activity
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsTriage: first grade,
bug·priority:p2·domain:cli·area:devpath·pm:queue. Direction: the verify handle boots whatserveboots, and gains the missing doorsTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T13:53Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/verify(harness.ts), with item 1 reusing the provider mapping frompackages/cli⇒domain:cli; rationale: verify sits with the CLI lane (as #15953 does).- Why p2: under the maintainer's B′ ruling on verify: an in-process handle on the booted stack — run a hook, flow, action or validation rule against the REAL engine and assert, so an app never fakes
ctx.apiagain (epic hotcrm#1579, step 5a) #15951, an app's tests run on the platform through this handle. Each gap forces hotcrm to keep one local path, and item 1 means an app's required capabilities are not even booted. - Item 1 first: move the capability-to-provider mapping (
CAPABILITY_PROVIDERS,CapabilitySpec) to a home bothserveandverifyread, so the handle boots the app'srequires[]exactly asservedoes. Then the remaining doors, one PR each or grouped by the seat. Clause-②: yesfor each new door on the published handle. The contract-review tier is owed.- Done when: each item deletes the matching hotcrm local path (hotcrm#1595's rule).
- Why p2: under the maintainer's B′ ruling on verify: an in-process handle on the booted stack — run a hook, flow, action or validation rule against the REAL engine and assert, so an app never fakes
- addedarea:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3
on Oct 8, 2026 objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsEvidence for item 9 (cel-dated seed replay under
bootStack), measured twice more by therepo:hotcrmseat's devs on hotcrm9451b6de/49fe305awith@objectstack/*17.7.0 (objectstack-ai/hotcrm#2016 report6062013748, objectstack-ai/hotcrm#2021 report6063336229).repo:hotcrmseat,session_012zh91QzFgePbkmuHnugLN3, 2026-10-08T15:35Z.- The rows: on every boot through
@objectstack/verify(3 of 3), the SeedLoader refusescrm_campaign#0 "Q3 Enterprise Email Nurture" and Implement ObjectStack protocol specification with Zod schemas and TypeScript interfaces #3 "Operations Platform Launch". Both arestatus: in_progresswith dates written as celdaysAgo(15)/daysFromNow(21)(hotcrmsrc/marketing/data/marketing.seed.ts:178-180,:223-227). The refusal is the app hook's own: "Campaign cannot move to in_progress without both start_date and end_date". Each of theircrm_campaign_memberrows then fails with "Campaign is required" (23 SeedLoader failures per boot). - The likely seam (NOT proven): the hook reads the dates only when
typeofis string (campaign.hook.ts:74-81). So the replay hands it either the unresolved cel envelope or a resolved non-string value (daysFromNowreturns a JSDate,formula/src/stdlib.ts). Which of the two this is decides whether the fix is the boot's (resolve and serialise asservedoes) or the app's. hotcrm WAITs on this card for that answer. - NOT MEASURED: an
objectstack devboot of the same commit, run for 150 s on fix(i18n): add view form end_user_controls translations #2016, logged neither refusal. So reach beyond the verify boot is unestablished.
Generated by Claude Code
- The rows: on every boot through
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsItem 9 narrowed: the seed divergence is the verify boot's. Measured by the dev of objectstack-ai/hotcrm#2018 on hotcrm
dc58e047, 17.7.0 (report6064159813).repo:hotcrmseat,session_012zh91QzFgePbkmuHnugLN3, 2026-10-08T16:16Z.objectstack dev -p 4925 --freshon a scratch SQLite file: all 7 seededcrm_campaignrows are stored, including "Q3 Enterprise Email Nurture" (dates 2026-09-23 → 2026-10-29) and "Operations Platform Launch" (2026-09-26 → 2026-10-22), plus 51crm_campaign_memberrows. No refusal.bootStack/bootStackOnceof the same artifact (memory and SQL): 46[SeedLoader] Failed to writelines per boot. The app'scampaign_validationrefuses those two campaigns, and every one of their members then fails "Campaign is required".
So the same cel-dated seed rows (
cel`daysAgo(..)`/cel`daysFromNow(..)`) reach the app's hook in a formserve/devnever hands it. The fix is on the verify boot's seed path; hotcrm builds nothing for it.
Generated by Claude Code
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsThis amends my grade (
6061416383):domain:cli→domain:spec. I graded this cardClause-②: yes, and perexecution-duties.md:101(「命中即 spec 车道的活」) anddispatch-gates: "a hit outside those lanes is spec-lane work and moves there" a widening of a published surface is spec-lane work wherever it lands. The landing (packages/verify, item 1 reusing the provider mapping frompackages/cli), the grade and the direction are unchanged. Thedomain:cliseat reviews the files in its own package.Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T16:58Z. ⛔ Not a claim, ⛔ not a dispatch.objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 (stage 1 of this card: items 1 and 9, "the handle boots what
serveboots", per triage6061416383's item-1-first direction) · 2026-10-08T18:08Z
Session:session_01DhTqaEHqPVSVnAkjG3jywn
Account:os-sales(the seat's linked user asGET /useranswers it; the card's assignee from this act)
Branch:claude/issue-22301-verify-boot-parity
Worktree:objectstack-issue-22301
Domain:domain:spec
Seat:domain:spec#2(seat post #18549)
File surface (atorigin/main28bff18d0or later; stop on breach and explain in the report):- Item 1:
packages/cli/src/commands/serve.tsServe.CAPABILITY_PROVIDERS(about:1870) andCapabilitySpec(about:962) move to one home that bothserveand@objectstack/verifyread (where it lives is measured: a packageverifyalready depends on, with no new cycle).packages/verify/src/harness.tsbootStackthen mounts the providers an app'srequires[]names, by the same ruleserveuses (top level when present, otherwise each package body, as PR fix(cli): os serve and seven sibling readers read a multi-package config's package-owned keys through its package bodies #22321 left it). Both readers are re-pointed in the same PR, ⛔ with no second copy of the mapping. - Item 9:
bootStack's seed replay hands a cel-dated seed value (cel`daysFromNow(..)`) to the engine in the formserve/devdo (seed-loader.tsabout:1138→formula/src/seed-eval.tsabout:74). The divergence is located first. The fix is on the verify boot's seed path, or on the shared seed loader if that is where verify diverges. - Tests in
packages/verify(arequires: ['…']app boots the provider; a cel-dated seed row is stored, the controls unchanged) and inpackages/clifor the moved mapping..changeset/22301-*.md. - ⛔ Not items 2–8 (new handle doors): each is a later stage on this card. ⛔ Not
packages/rest. - Declared cross-lane files:
domain:cli(packages/verify,packages/cli), declared on [PM seat] domain:cli — 🟢 os-elon-musk · session_01BmsuLyUeuG5CNpZFMH1jzS #6024.domain:engine(packages/metadata-protocol/src/seed-loader.ts,packages/formula) only if item 9's fix lands there, declared on [PM seat] domain:engine — ⏳ vacant #6367 when it does.
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectstackon these paths: no path-derived mandate; the default tier). A contract review atCONTRACT_REVIEW_TIERis owed before enqueue (this claim'sClause-②: yes), from an isolated at-tier subagent.
Clause-②: yes (widening:bootStackmounts the providers an app requires, and the provider mapping gains a public home both readers import)
Responsibility:packages/verify'sbootStackboots a fixed plugin set and replays seeds unlikeserve| none: the handle is the only platform path for an app's tests under the maintainer's B′ ruling on verify: an in-process handle on the booted stack — run a hook, flow, action or validation rule against the REAL engine and assert, so an app never fakesctx.apiagain (epic hotcrm#1579, step 5a) #15951 | every app testing through@objectstack/verify; hotcrm measures both (test: run the hook, flow and action suites on @objectstack/verify and retire the five hand-built harnesses hotcrm#2013, hotcrm reports6062013748,6063336229,6064159813)
Thread-read: 6064912705
Serial constraints cleared: - PR fix(cli): os serve and seven sibling readers read a multi-package config's package-owned keys through its package bodies #22321 (
serve.ts, the multi-packagerequiresreader) has landed as28bff18d0, the base of this claim, and [finding] cli(serve):os serveresolves capability providers from a multi-package artifact's top-levelrequiresonly — a package'srequires: ['automation']is not loaded at boot #22288 is closed with it. The dev works on the merged code. - No open PR touches
packages/verify/src/**,serve.ts,seed-loader.tsorformula/src/seed-eval.ts(14 open PRs read at this stamp; the Version Packages PR chore: version packages #21988 touches onlypackages/verify/CHANGELOG.mdandpackage.json). area:devpathis also on this seat's [maintainer] validate: thefield-no-consumerswarning is one 856-character line, printed by validate, build and dev alike — one-line verdict +rule:id + a pointer to the full reasoning (os explain, which today takes only schema names) #22161 (packages/lint,packages/cli/src/commands/explain.ts): the file surfaces are disjoint.
- Item 1:
56 remaining items
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsClaim: PM loop round 2 (item 8 of this card: the verify handle fronts the automation engine's condition evaluator) · 2026-10-09T23:38Z
Session:session_01KNKBCRDJCu5tGy3TEbvtrF
Account:zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee from this act)
Branch:claude/issue-22301-evaluate-condition
Worktree:objectstack-issue-22301-evaluate-condition
Domain:domain:spec(per triage's amendment6064912705)
Seat:domain:spec#3(seat post #18883)
File surface (atorigin/maindb9cf804d6; stop on breach and explain in the report):packages/verify/src/handle.ts: the handle's door surface.harness.tsonly where the door needs the booted kernel'sautomationservice. Tests go underpackages/verify/src/,packages/verify/src/index.tschanges if a new type is exported, the handle's door roster and README line, and.changeset/22301-*.md(@objectstack/verifyminor).- Premise first (a reading, before any edit). On this base, is there still no handle door to the engine's predicate evaluator,
AutomationEngine.evaluateCondition(packages/services/service-automation/src/engine.tsabout:12225)? Read the handle, the booted kernel'sautomationservice, and hotcrm's localconditionHoldspath as the card describes it.- If a door exists, the item reduces to pins.
- If not, the handle gains one door. It calls the engine's own evaluator on the booted kernel, with the same input shape (a CEL envelope or source plus variables), and does not re-derive or re-implement it.
- ⛔ No change in
packages/services/**,packages/spec/**orpackages/rest. ⛔ Items 5, 6, 7 and item 1's remaining gap are not this claim.
Container & model:S,mode:subagent,model: default tier(dispatch-gates --tier: no path-derived mandate). A new public member of a published package's handle: the contract review atCONTRACT_REVIEW_TIERis owed before enqueue.
Clause-②: yes (widening)
Responsibility:packages/verify's handle has no door to the engine's predicate evaluator | no platform path covers it (hotcrm keeps a local path calling the kernel service) | who reaches it: any app testing a condition truth table through@objectstack/verify, measured by hotcrm's ported suite on 17.7.0
Thread-read: 6090871332
Serial constraints cleared: the 13 open PRs' file lists, read at 2026-10-09T23:38Z. None touchespackages/verify/**. Items 2–3 (PR feat(verify): the handle gains a system-context update door and a predicate update door #22517) and item 4 (PR test(verify): pin the anonymous public-form door a booted stack already serves #22543) have landed. Seat 2 released its claim in6090871332.
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 22301,
"status": "done",
"branch": "claude/issue-22301-evaluate-condition",
"pr": "#22553",
"session": "session_01KNKBCRDJCu5tGy3TEbvtrF",
"premise_still_valid": true,
"summary": "Item 8 only. The handle gains stack.automation.evaluateCondition(condition, variables): it resolves the booted kernel's automation service at call time (kernel.getServiceAsync, the lookup the handle's engine doors use and the dispatcher's flows route makes first), calls the engine's own evaluateCondition with the condition as given (its parameter type is read off the engine method) and the variables as the Map the engine takes, and resolves with the engine's boolean; no second evaluator, no dialect re-derivation, no catch. With no automation service the door rejects with the kernel's own branded SERVICE_NOT_REGISTERED error naming 'automation', so no error code is minted and packages/spec is untouched. Name: 'automation' is the kernel slot and 'evaluateCondition' the engine method, so the door reads as the call it makes (as tenancy() is named after its slot); the flows group was rejected because its doors are dispatcher routes run as a caller and this one has no caller. Resume note (container restart): the worktree read clean at 86bf9ed with only the empty write probe pushed and no edits made, so nothing was lost; the lock and background processes were re-taken per suite.",
"tests": "All at HEAD 79e9053 unless named. (1) Closure build: pnpm turbo run build --filter='@objectstack/verify^...' --concurrency=2 under os-verify-lock: 46/46 tasks, VERDICT command-exit 0. (2) New pins, packages/verify/src/handle.automation-door.test.ts: 6/6 (spy on the booted service: one call, same envelope object, Map entries equal the variables, return value is the door's answer; truth table over record/previous true x1 false x2, equal to the engine called directly; envelope and bare CEL string alike; a bare '{amount} > 100' keeps the template dialect and the spy sees the string, the same text in a CEL envelope rejects with the engine's own message; a CEL parse error and an unbound variable reject with the engine's own error, not a VerifyRefusal, no code; no-automation boot rejects with SERVICE_NOT_REGISTERED, serviceName 'automation', brand predicate true, same message as the kernel asked directly). (3) @objectstack/verify full suite (vitest run --maxWorkers=2): 26 files / 209 tests pass, run at 0aac167; the one later commit is a docblock re-wrap in harness.ts, after which build + typecheck + the door file reran green at 79e9053. (4) Typecheck: tsc --noEmit + check:test-typecheck exit 0; --listFiles on tsconfig.test.json lists the new file (1 of 26 verify test files). Reverse type check: a one-off probe passing 42 as the condition reds tsc with TS2345 naming the engine's parameter type (string or the dialect/source/ast envelope); probe deleted, git status clean. (5) Ablations on the committed head via node scripts/ablation-replace.mjs (WRAP mode, anchor hit 1 -> 0, blob 4b419e0784 -> changed, restore proven blob == HEAD 4b419e0784 and git diff HEAD empty): A, door answers around the engine (stand-in never calls it): predicted 5 red / 1 green, observed 5 red / 1 green (no-service pin green, the kernel answers first); B, door wraps a string as a CEL envelope (the hotcrm helper's re-derivation): predicted only the dialect pin red, observed only that pin red ('condition failed to evaluate as CEL: Expected COLON, got RBRACE'). The subject resolves to src/ through relative imports, so no dist rebuild is part of either leg (ablation-dist-preflight not applicable).",
"mcp_calls": "0",
"api_writes": "3 relay strokes (fleet-write repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches, each executed as objectstack-fleet[bot]): pr_create -> POST /repos/objectstack-ai/objectstack/pulls (#22553, draft, body read back byte-identical, 8388 bytes); label-write assign -> POST /repos//issues/22553/assignees (zhuangjianguo, read back matches; no label written); this os-dev-report comment -> POST /repos//issues/22301/comments. Plus git push (not REST). Reads: REST GET of the card, its comments, the PR and its check-runs; the three PR-context guards read with the session token.",
"open_questions": [
{
"question": "Non-blocking, for the contract review: should the no-automation answer stay the kernel's own SERVICE_NOT_REGISTERED rejection (names the service, carries code and serviceName, no status, no remedy sentence), or become a verify-owned refusal carrying the remedy (automation: true, or requires: ['automation'])?",
"options": [
"A (landed): hand back the kernel's rejection unchanged; the remedy lives in the JSDoc and README. Real need: hotcrm's suites boot with automation declared, the empty slot is a one-time composition mistake, and no caller is measured asking for a remedy sentence. Long-term: one vocabulary, core's published discriminator for exactly this (isServiceNotRegisteredError), the same answer the handle's engine doors already give for an empty objectql slot. AI-error: the message names the service; the fix is in the JSDoc an author reads at the call site, weaker than a message that names it. Scope: adds nothing.",
"B: catch the branded rejection and rethrow a verify-owned refusal with the remedy. Real need: none measured. Long-term: a second spelling of one fact at the in-process layer. AI-error: the message names the fix directly, which helps. Scope: a new code under @objectstack/verify needs an ERROR_CODE_LEDGER row in packages/spec plus an @objectstack/spec changeset, the surface this claim excludes."
],
"recommendation": "A, because it adds no vocabulary or spec surface, matches the handle's existing engine-door answer for an empty slot, and the one axis B wins (a remedy in the message) is covered by the JSDoc at the call site; B stays available as a later widening if a real author is measured missing it."
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted in PR #22553 Acceptance notes, not filed: the door types the automation slot as the engine class because evaluateCondition is not on IAutomationService (as engine types objectql as ObjectQL); another provider under that slot would answer a TypeError here; one producer of the slot in packages/ today (service-automation plugin.ts:975), so no reach.",
"carrier: 承接者:无 · noted in PR #22553 Acceptance notes, not filed: for 'no automation service' the handle's two automation surfaces answer differently by design: flows.* (a route door) gets the dispatcher's 501 for an empty slot (read from runtime domains/automation.ts:2374, not measured on a boot), this engine door gets the kernel's in-process error; the split the handle already documents between route doors and engine doors."
],
"gates": "Derived: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) at 79e9053 = 64 families, same list as at 0aac167; 2 more than the PM's dispatch-time list (pnpm check:error-status-conformance, pnpm check:swallow-census-controls), both run. 63 ran, each exit 0; NOT MEASURED: dual-build-cjs-loads, reason: needs a whole-workspace build, which the dispatch excludes; declared to CI. --ran reconciliation (exit-coded record): 64 derived, 63 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. Artifact-roster block: 52/52 ran, exit 0: 49 at 79e9053 (check:error-code-provenance: 2829 files, 337 registered-code stamp sites, 318 listed, 19 waived, OK; check:error-code-casing OK) plus the 3 PR-context guards wired to PR #22553 (PR_NUMBER, PR_BODY, PR_HEAD_REF, GITHUB_REPOSITORY, a read token): check-closing-target-claim exit 0 (binds no closing keyword), check-partof-closing-keyword exit 0 (no contradiction), check-single-claim-paths exit 0 (none of the 1 declared path touched). Spot verdicts: check:nul-bytes OK over 10553 files; check:issue-citations 3 citations resolve; check:doc-authoring clean; check:slot-lookup ratchet holds; check:dts-closure 47 built packages, 142/142 d.ts; check:published-files OK; check:cross-package-test-inputs OK; check:test-source-alias OK. Not owed locally and declared to CI: other packages' full suites, pnpm lint (repo-wide eslint). CI on the PR at report time: 11 success, 3 skipped, 17 in_progress, 0 failed (in_progress is the honest value; not waited on).",
"line_budget": "5 files, +294 / -7 = 301 changed lines vs the 3000-line human-merge threshold: under. No governed surface (no .claude/, skills/, docs/adr/**, AGENTS.md, CLAUDE.md), so no skills line budget applies. Source +63/-2 (handle.ts +60, harness.ts +3/-2), test +198, README +19/-5, changeset +14.",
"deviations": [
"packages/verify/src/harness.ts touched for a docblock only (the VerifyStack member list gainsautomation); the claim allows harness.ts only where the door needs the kernel's automation service, but the list would otherwise be false after this change.",
"Zone 3 asked for a typed refusal naming the missing service: delivered as the kernel's own branded SERVICE_NOT_REGISTERED rejection (code, serviceName 'automation', brand), not a verify-minted refusal; that keeps packages/spec untouched (a new code would need a ledger row the claim excludes). It carries no status by core's design, so its pin asserts code + serviceName + the brand predicate + message equality with the kernel asked directly instead of code + status. See open_questions[0].",
"Zone 3 asked for one ablation leg; two ran (around-the-engine, and the string-wrap re-derivation), each restored blob-equal.",
"The full verify suite ran at 0aac167, not the final head; the one later commit (79e9053) re-wraps a docblock in harness.ts, after which build, typecheck and the new test file reran green at the final head.",
"Zone 2 assumption 2 named anapidoor on the handle;apiis on VerifyStack (harness.ts), not the handle (handle.ts). Not material.",
"Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude) and the PR body uses AGENTS.md's session-URL footer, over the harness reminder's model-named trailer and footer form, per the dev definition's precedence rule.",
"The container restarted mid-run (PM note). State on resume: worktree clean at 86bf9ed, remote branch equal, no edits made yet, scratchpad intact; work continued from the premise reading.",
"origin/main moved one commit since BASE (4638625, packages/cli only, outside verify's closure); no merge was made."
],
"files_changed": [
".changeset/22301-verify-evaluate-condition-door.md (+14): @objectstack/verify minor, Clause-②: yes (widening)",
"packages/verify/src/handle.ts (+60): door roster entry, AutomationCondition type read off the engine method, VerifyHandle.automation.evaluateCondition with JSDoc, implementation",
"packages/verify/src/handle.automation-door.test.ts (+198): 6 pins over two boots",
"packages/verify/src/harness.ts (+3/-2): VerifyStack member list docblock",
"packages/verify/README.md (+19/-5): handle section, example, refusal bullet, API list, automation boot option"
]
}
Generated by Claude Code
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actions✅ ACCEPT: PR #22553 at
79e9053e50(item 8,Part of #22301). The contract review atCONTRACT_REVIEW_TIERis owed before it landsdomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-10T00:33Z · holder of claim6091117720. Report:os-dev-report6091573005. Thread-read: 6091573005.Checked in the diff, not taken from the report (5 files, +294 / −7):
-
The door:
stack.automation.evaluateCondition(condition, variables).- It resolves the
automationservice off the kernel at call time and calls the engine's ownevaluateCondition. The condition is passed as given; its type is read off the engine method asParameters<AutomationEngine['evaluateCondition']>[0]. The variables are passed as theMapthe engine takes. - It resolves with the engine's boolean. There is no second evaluator, no dialect rewrite and no catch.
@objectstack/service-automationis already a runtime dependency of@objectstack/verify, so the type import adds no package edge.
- It resolves the
-
The pins: 6, over two boots. They cover:
- the spy-identity call;
- a truth table equal to the engine called directly;
- the envelope and the bare string, and the template-dialect string the door must not rewrite;
- the engine's own rejection on a parse error and on an unbound variable;
- the kernel's
SERVICE_NOT_REGISTEREDon a boot without automation.
Two ablation legs ran: around the engine, and the string-wrap re-derivation. Each went red as predicted, and each restore was blob-equal.
-
The changeset:
@objectstack/verifyminor,Clause-②: yes (widening). The PR's first line isPart of #22301, with no closing keyword.
The open question, answered by the seat under existing norms: A.
- A boot without automation hands back the kernel's own
SERVICE_NOT_REGISTEREDunchanged. The handle's engine doors already answer an emptyobjectqlslot the same way, so this keeps one vocabulary, and no error code orpackages/specledger row is minted. - The remedy (
automation: trueorrequires: ['automation']) is in the JSDoc and the README.
Evidence, as reported, with its shape checked:
- the closure build;
- the full
@objectstack/verifysuite, 26 files / 209 tests; - typecheck, including the test layer;
- the derived 64 families, 63 at exit 0, with
dual-build-cjs-loadsNOT MEASURED as dispatched; - the roster block, 52/52,
check:error-code-provenanceincluded.
Acceptance notes carried, no carrier:
- the slot typed as the engine class, since
evaluateConditionis not onIAutomationService; - the route door (
flows.*, the dispatcher's 501) and this engine door (the kernel's error) answering an empty slot differently, by the handle's documented split.
Next: the PR stays a draft, marked
needs:contract-review, until a same-head PASS is on record. Items 5–7 and item 1's remaining gap stay on this card.
Generated by Claude Code
-
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 22301,
"status": "done",
"branch": "claude/issue-22301-evaluate-condition",
"pr": "#22553",
"head": "1582733139",
"session": "session_01KNKBCRDJCu5tGy3TEbvtrF",
"premise_still_valid": true,
"summary": "Patch round on the PM order (CI red at 79e9053: @objectstack/dogfood#typecheck TS2741, 'automation' missing from a hand-built VerifyStack literal). One line added: packages/qa/dogfood/test/rls-runner.test.ts gainsautomation: undefined as never,beside the other handle members the fake stack types as never (contextFor, hooks, validate, flows, actions, seed, rows, metadata, tenancy); nothing else in the test changed. A typed grep found no other hand-built VerifyStack/VerifyHandle literal in packages/, examples/, apps/, skills/ or content/docs:contextFor:as an object key appears only in that file outside packages/verify/src; every function typed to return VerifyStack/VerifyHandle returns bootStack's or createHandle's result; the only consumers of @objectstack/verify are cli (no Verify type reference), plugins/organizations (variable annotations only) and qa/dogfood. New head 1582733; CI there: 32 success, 3 skipped, 0 failed. The worktree was recreated from the pushed branch (it had been removed after the first report), and removed again after this report.",
"tests": "At 1582733, under os-verify-lock. (1) Dogfood closure build: pnpm turbo run build --filter='@objectstack/dogfood^...' --concurrency=2: 63/63 tasks, 63 cached (FULL TURBO), VERDICT command-exit 0; the replayed verify dist carries the door (evaluateCondition: 3 hits in dist/index.d.ts). (2) pnpm --filter @objectstack/dogfood typecheck: exit 0. (3) pnpm --filter @objectstack/verify typecheck: exit 0 (check:test-typecheck OK). (4) src/handle.automation-door.test.ts: 6/6. (5) Control leg for the fix, via node scripts/ablation-replace.mjs --delete on the new line: dogfood typecheck red with exactly CI's error, 'test/rls-runner.test.ts(118,3): error TS2741: Property 'automation' is missing in type ...', exit 2; restored blob == HEAD (1f2aff3774e5), git diff HEAD empty. The verify full suite (26 files / 209 tests at 0aac167) is not rerun: this round's only change is a type-only stub in a dogfood test file outside verify.",
"mcp_calls": "0",
"api_writes": "1 relay stroke this round: this os-dev-report comment -> POST /repos//issues/22301/comments (via fleet-write repository_dispatch). Plus git push. No PR body edit, no label or assignee write. Running total for the dispatch: 4 relay strokes (pr_create, assign, two reports).",
"open_questions": [],
"out_of_scope_findings": [],
"gates": "Re-derived at 1582733 (path set now includes packages/qa/dogfood/test/rls-runner.test.ts): 68 families, 4 more than at 79e9053 (pnpm --filter @objectstack/spec run check:empty-state, check:liveness, check:strictness-ledger, check:variant-docs). 67 ran, each exit 0; NOT MEASURED: dual-build-cjs-loads, reason: needs a whole-workspace build, which the dispatch excludes; declared to CI. --ran (exit-coded record): 68 derived, 67 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. Artifact-roster block, 51 rows at this head (check:strictness-ledger moved into the derived set): 48 ran at 1582733, each exit 0 (check:error-code-provenance OK, 10 waivers all live), plus the 3 PR-context guards wired to PR #22553 at head 1582733: closing-target-claim, partof-closing-keyword, single-claim-paths, each exit 0. Union: 113 commands run, 0 non-zero. CI at 1582733: 32 success, 3 skipped, 0 failed.",
"line_budget": "6 files, +295 / -7 = 302 changed lines vs the 3000-line threshold: under. This round: +1 line.",
"deviations": [
"The claim's file surface widened to the one consumer literal the PM order names: packages/qa/dogfood/test/rls-runner.test.ts (+1 line). No other edit.",
"Root cause of the red, owned: the first round added a required member to the exported VerifyHandle interface (a public-surface change) and did not typecheck verify's import-side consumers; dispatch-gates derived no qa/dogfood family because no dogfood path was in the change set.",
"The PR body was written once at 79e9053 and is not patched (dev rule). For the seat to write: under 'What lands', add a bullet: packages/qa/dogfood/test/rls-runner.test.ts, the hand-built VerifyStack literal stubsautomation: undefined as neverbeside the other handle members it does not model; and under 'Evidence', move the head to 1582733, gates 68 derived / 67 run / 1 NOT MEASURED / 0 UNRUN, rosters 51, dogfood typecheck exit 0 with the TS2741 control leg.",
"The seat's ACCEPT 6091663799 names 79e9053; the head is now 1582733 (one added line in a dogfood test file).",
"origin/main is at 6a3f82e (4 commits past BASE 86bf9ed); none touches packages/verify, the dogfood rls-runner test or the engine's evaluator; no merge made."
],
"files_changed": [
"packages/qa/dogfood/test/rls-runner.test.ts (+1):automation: undefined as never,in fakeStack's VerifyStack literal (this round)",
".changeset/22301-verify-evaluate-condition-door.md (+14), packages/verify/src/handle.ts (+60), packages/verify/src/handle.automation-door.test.ts (+198), packages/verify/src/harness.ts (+3/-2), packages/verify/README.md (+19/-5) (first round, unchanged)"
]
}
Generated by Claude Code
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsLanded: PR #22553 →
fbb065fd4b(item 8,Part of #22301). The card goes back topm:queuefor items 5–7 and item 1's remaining gapdomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-10T01:39Z · holder of claim6091117720, released by this act.Release:
session_01KNKBCRDJCu5tGy3TEbvtrF· why: item 8 has landed; the claim covered item 8 only · to:pm:queue, unassigned.- Landed: through the merge queue at 2026-10-10T01:35Z as
fbb065fd4b, a squash with one parent,20e7d52097(PR feat(spec)!: atype: 'chart'list view whose effective binding names no dataset is refused at every list-view door #22528, from the same queue group). The queue did not eject it. - Content check: all 6 PR paths on
fbb065fd4bare blob-equal to the reviewed head1582733139. The contract review PASS6092010308names that head.mainmoved none of the six between the merge base86bf9ed7d5and the queue base. - What now holds (
@objectstack/verifyminor,Clause-②: yes (widening)):stack.automation.evaluateCondition(condition, variables)calls the automation engine's ownevaluateCondition. The accept-set is the engine's by type, and the verdict and the faults are the engine's, unchanged. A boot without automation answers with the kernel's ownSERVICE_NOT_REGISTERED. The remedy (automation: true, orrequires: ['automation']) is in the JSDoc and the README. - What remains on this card, for whichever seat takes it:
- item 5 (a user-less insert / delete trigger and a deleted-record flow);
- item 6 (observing what a hook handed the engine);
- item 7 (a lowered-body door);
- item 1's remaining composition gap (
6081449527).
- Acceptance notes carried, not filed:
- the slot is typed as the engine class, since
evaluateConditionis not onIAutomationService; - the route door (
flows.*, the dispatcher's 501) and this engine door (the kernel's error) answer an empty slot differently, by the handle's documented split.
- the slot is typed as the engine class, since
- Mis-close scan: the PR carries no closing keyword; the card stays open, and no card names
fbb065fd4b.
This act moves the card
pm:dispatched→pm:queueand removes this seat's assignee; the domain, area, priority and type labels stay.
Generated by Claude Code
- Landed: through the merge queue at 2026-10-10T01:35Z as
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsClaim: PM loop round 2 (item 5 of this card: a user-less record trigger, and a record the engine no longer holds —
hooks.runtakes{ system: true }oninsertanddelete) · 2026-10-10T01:54Z
Session:session_01KNKBCRDJCu5tGy3TEbvtrF
Account:zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee from this act)
Branch:claude/issue-22301-system-insert-delete-door
Worktree:objectstack-issue-22301
Domain:domain:spec
Seat:domain:spec#3(seat post #18883)
File surface (atorigin/mainfbb065fd4b; stop on breach and explain in the report):packages/verify/src/handle.ts:hooks.run's{ system: true }arm, today refused oninsertanddelete(about:486–:490), and the overload set and its JSDoc (about:189–:205).packages/verify/src/harness.ts: docblock only, where the door roster names the system door.packages/verify/README.md.- Pins in
packages/verify/src/(or itstest/, wherever the item 2–3 pins live). - Any consumer that hand-builds the handle's type and fails its typecheck (the item 8 lesson:
packages/qa/dogfood/test/rls-runner.test.ts's fake stack). .changeset/22301-*.md(@objectstack/verifyminor,Clause-②: yes (widening)).- ⛔ Items 6, 7 and item 1's remaining gap are not in this claim.
Container & model:S,mode:subagent,model: default tier(dispatch-gates --tier: no path-derived mandate). A widening of a published handle: the contract review atCONTRACT_REVIEW_TIERis owed before enqueue.
Clause-②: yes (widening)
Responsibility:@objectstack/verify'shooks.runrefuses a system insert or delete, so an app test cannot drive a record-change flow fired by a user-less write, nor a flow whose record was deleted before itsget_record| no platform path covers it (seedskips record-change flows; items 2–3 gaveupdateonly) | who reaches it: hotcrm'srunRecordFlowlocal path (test/helpers/verify-stack.ts), per the card body
Thread-read: 6092275704
Serial constraints cleared: the file lists of the 12 open PRs, read at 2026-10-10T01:54Z. None touchespackages/verify/**. Item 8 (PR feat(verify): the handle fronts the automation engine's condition evaluator #22553) has landed (fbb065fd4b); no other claim on this card is in flight.
This act moves the card
pm:queue→pm:dispatchedand assignszhuangjianguo.
Generated by Claude Code
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 22301,
"status": "done",
"branch": "claude/issue-22301-system-insert-delete-door",
"pr": "#22596",
"session": "session_01KNKBCRDJCu5tGy3TEbvtrF",
"premise_still_valid": true,
"summary": "Item 5. hooks.run(object, 'insert' | 'delete', input, { system: true }) now runs. It is the same engine call a person's write makes (ql.insert / ql.delete), under { isSystem: true }. The bound hooks see the system and no user, declared validations still refuse, the record-change trigger fires the object's flows with no trigger user, and no permission gate applies. A call naming both callers is still refused INVALID_REQUEST / 400 before the engine is touched. Zone 2 was measured on a booted stack before the door was opened. Assumption 1 held: the refusal was at handle.ts:486-491, and the arms already made the engine calls. Assumption 2 held: both system writes fire the record-change flow user-less, through the engine's own hook dispatch, and only skipTriggers suppresses it. Assumption 3 held for a delete-triggered flow: a record-after-delete flow is handed the pre-image as record and as previous, and its get_record of that id finds no row (a record-before-delete flow on the same delete finds it). Assumption 4: seed is unchanged and still fires no record-change flow, which is pinned. Pinned by 7 tests in a new file, with two ablations, each red in its predicted direction. The README and a minor changeset are written. The pending items 2-3 changeset carried a sentence this change makes false ('Only update takes it'), and it is corrected. The check-empty-changeset gate and CI 'Check Changeset' are RED on that by design (the DELIBERATE CORRECTION class) and need a person's confirmation on the PR. Not served, and raised in open_questions: an UPDATE-triggered flow over a row deleted between its trigger and its get_record, which is hotcrm's ghost case. Of hotcrm's 8 runRecordFlow call sites (f0afcbd), 4 are served (system insert), 3 are likely served but not measured on hotcrm, and 1 is not served (that ghost case).",
"tests": "Final head 84a4a1e is the merge of origin/main 25be876, which touches none of the PR's paths. (1) Dependency closure: pnpm exec turbo run build --filter='@objectstack/verify^...' --concurrency=2, run under os-verify-lock after the merge: 46/46 tasks, VERDICT command-exit 0. (2) The @objectstack/verify full suite (vitest run --maxWorkers=2) at 84a4a1e: 27 files / 216 tests passed, VERDICT command-exit 0. (3) New pins, src/handle.system-insert-delete.test.ts, 7/7 green, together with src/handle.update-doors.test.ts 9/9 (16/16, VERDICT command-exit 0, at 915f88e). Their first run was red 6/7, from a fixture bug: the rule comparing priority greater than 5 faulted on a null priority. That was fixed in the fixture by adding a != null guard, which is the engine's own prescription in its message. (4) Typecheck: pnpm --filter @objectstack/verify typecheck (tsc --noEmit + check:test-typecheck) exit 0 at 915f88e and again at 84a4a1e. tsc -p tsconfig.test.json --listFiles lists 27/27 of the package's src test files, the new one included (TSC_EXIT=0). (5) Consumer typecheck: the closure turbo build --filter='@objectstack/dogfood^...' (63/63, with @objectstack/verify a cache miss), then pnpm --filter @objectstack/dogfood typecheck: exit 0 (at 915f88e). The rebuilt verify dist/index.d.ts carries the widened overload once and the old 'update'-only AsSystem overload zero times. (6) Reverse check from dogfood against the rebuilt .d.ts. A scratch file calling hooks.run('o','insert'|'delete',..., { system: true }) compiled (exit 0). Adding 'upsert' turned tsc red, exit 2, with TS2769 'No overload matches this call'. The file was removed under a trap and git status is clean. (7) Ablations, on committed head 915f88e, through scripts/ablation-replace.mjs inside the verify lock. Each anchor went 1 → 0, the blob changed, and the file was restored to HEAD blob a6e175d1c0d3 with git diff HEAD empty. A1 put the update-only refusal back. Predicted: 6 system insert/delete pins red, the two-caller pin and the 9 update-door pins green. Observed: 6 failed / 10 passed, and each failure is the ablation's own refusal (6 hits of its message). A2 handed SEED_CONTEXT instead of SYSTEM_CONTEXT. Predicted: the 3 new flow-run pins plus the item 2 flow pin red, the row-level pins green. Observed: 4 failed / 12 passed, exactly those four. Each ablation's direction was predicted before its run. A1 took three attempts. The first was refused by the tool before anything ran, because its replacement contained the anchor. The second never acquired the lock (exit 99, NOT MEASURED) and was restored. The third is the one reported. (8) The Zone 2 measurement probe (scratch, deleted, never committed): the readings quoted in the PR body, including ql.delete answering true, and a readonly field kept by a system insert but stripped from an admin's.",
"mcp_calls": "0",
"api_writes": "3 relay strokes. Each is a repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]: (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (#22596, draft): 11017 bytes sent and stored, identical, read back again by REST; (2) label-write --assign → POST /repos//issues/22596/assignees (zhuangjianguo): read back matches, and no label was written ('size/l' was present from the labeler and preserved); (3) this os-dev-report comment → POST /repos//issues/22301/comments. Plus git push (not REST). Reads: REST GETs of the card, its comments, the PR and its check-runs, the relay route read, and the 3 PR-context guards run with the session token. A hotcrm sparse clone (git, read-only) was used to read test/helpers/verify-stack.ts and its callers; it has been deleted.",
"gates": "Derived after the last commit: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths), at 84a4a1e, with no stale-tree warning: 63 commands, the same list as at 915f88e. That list adds 7 to the dispatch-time list: check-adr-0087-registration (base + self-test), check-empty-changeset (base + self-test), release-rehearsal-clone --self-test, release-pending-publish --self-test, check:error-status-conformance, check:objectui-changeset and check:pm-changeset-deadline-census. All of them were run. The PM's 4 spec families absent from this derivation (check:empty-state, check:liveness, check:strictness-ledger, check:variant-docs) were also run, all exit 0. Results: 61 exit 0. One exit 1: node scripts/check-empty-changeset.mjs --base origin/main, the DELIBERATE CORRECTION class on .changeset/22301-verify-update-doors.md. It is red by design, needs confirmation, and is not a failed measurement. NOT MEASURED: pnpm check:dual-build-cjs-loads, reason: whole-workspace build excluded by the dispatch; left to CI. --ran reconciliation over the exit-coded record: 63 derived, 62 run, 1 NOT-MEASURED, 0 UNRUN, exit 0. Artifact rosters: 52/52 ran and all exit 0. That is 49 at 84a4a1e, plus the 3 PR-context guards wired to PR 22596 (PR_NUMBER, PR_BODY, PR_HEAD_REF, GITHUB_REPOSITORY, a read token): check-closing-target-claim exit 0 (binds no closing keyword), check-partof-closing-keyword exit 0, and check-single-claim-paths exit 0 (none of the 1 declared path touched). Spot verdicts: check:error-code-provenance 2835 files, 335 stamp sites, 317 listed, 18 waived, OK. check:error-code-casing OK over 8024 files. check-changeset-fixed in sync. check:published-readme-exports OK. check:nul-bytes OK over 10580 files. Not owed locally and declared to CI: other packages' suites and pnpm lint. CI at report time on 84a4a1e: 10 success, 3 skipped, 17 in_progress, 1 failure. The failure is 'Check Changeset', whose annotation is the same DELIBERATE CORRECTION refusal on .changeset/22301-verify-update-doors.md.",
"line_budget": "6 files, +455 / -45 = 500 changed lines, under the 3000-line human-merge threshold. No governed surface, so no skills line budget applies. By file: handle.ts +34/-23, new test +384, handle.update-doors.test.ts +6/-12, README +16/-9, new changeset +14, items 2-3 changeset +1/-1.",
"deviations": [
".changeset/22301-verify-update-doors.md was edited. It is the pending, unreleased items 2-3 release note, inside the claim's .changeset/22301-*.md surface. Its sentence 'Only update takes it. { system: true } on insert or delete ... is refused' became false with this change, so it is corrected to keep only the two-caller refusal and point at this entry. check-empty-changeset and CI 'Check Changeset' stay red until a person confirms it on the PR; no skip-changeset label was used.",
"packages/verify/src/harness.ts was not touched. Its docblock lists the handle's members generically and names no system door, so nothing in it became false.",
"origin/main (25be876, 3 commits, none on this PR's paths) was merged before the PR was opened, per AGENTS.md section 10. The closure was rebuilt, and the full suite, verify typecheck, listFiles and all gates ran at the merge head. The ablations, the dogfood consumer typecheck and the reverse check ran at 915f88e, the pre-merge head with the same PR content.",
"Ablation A1 took three attempts. The first was refused by ablation-replace with nothing run (its replacement contained the anchor). The second hit queue-timeout 99 and is NOT MEASURED; the tool restored the file. The third, with the mutation inside the lock, is reported. This is declared, not silently retried.",
"Two ablations ran where Zone 3 asked for one. The second (seed context for system context) shows that the trigger pins tell this door from a seed-like door.",
"Commit trailers use AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), and the PR body uses AGENTS.md's session-URL footer, over the harness reminder's model-named trailer and footer form, per the dev definition's precedence rule.",
"The PM's dispatch-time gate file listed 58 commands from a stale tree. This run derived 63 at the final head. Both lists are covered."
],
"files_changed": [
"packages/verify/src/handle.ts (+34/-23): the update-only refusal is removed. The AsSystem overload of hooks.run widens to 'insert' | 'update' | 'delete', and its JSDoc gains the delete-flow and seed contrast. The AsSystem docblock and the door-roster header are updated.",
"packages/verify/src/handle.system-insert-delete.test.ts (+384, new): 7 pins on one boot.",
"packages/verify/src/handle.update-doors.test.ts (+6/-12): the pin asserting the old insert/delete refusal keeps only its two-caller leg.",
"packages/verify/README.md (+16/-9): the handle example (system insert + delete), the caller bullet (seed vs a system write), and the refusal bullet.",
".changeset/22301-verify-system-insert-delete-door.md (+14, new): @objectstack/verify minor, Clause-②: yes (widening).",
".changeset/22301-verify-update-doors.md (+1/-1): the pending sentence corrected (see deviations)."
],
"open_questions": [
{
"question": "Item 5's second half for an UPDATE-triggered flow: does the card need a handle door for a flow over a row deleted between its update trigger and its get_record (hotcrm test/flow-escalation-ownerless-case.test.ts:233, the 'ghost' case, which runs the shipped case_escalation flow), or is that door out of scope? Measured: the engine runs a record-change flow inside the write, while it still holds the row. The run is in listRuns when the write returns, as the item 2-3 pins already rely on. So no write produces that state, and the delete door only reaches it for a delete-triggered flow.",
"options": [
"A: State the door out of scope for the handle. hotcrm keeps that one runRecordFlow path (it calls the engine's own automation.execute on the verify-booted kernel, which B-prime permits for a behaviour the handle cannot express), or retires the case.",
"B: Front automation.execute(flowName, { record, object, event }) as a handle door, the way item 8 fronted evaluateCondition, so a test can hand a flow any record."
],
"recommendation": "A, on the four axes. Real business need: one consumer test site measured, zero production producers. The shipped case_escalation flow has no wait or screen node, so in production its run is synchronous inside the write and never sees its row gone. Long-term soundness: B hands the engine a record the trigger never built. automation.execute with a hand-built record skips RecordChangeTrigger.buildContext (declared-field materialization, computed-field hydration, decoupling), so the flow would see a record shape no trigger produces, which is the stand-in the handle's design rule forbids. Hard for AI to get wrong: B lets a test go green on a state no write produces, which says nothing about production, while A keeps tests on real writes. Startup focus: A adds no surface; B adds a public member with one consumer site."
}
],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted in PR 22596's Acceptance notes, not filed. hooks.run(..., 'delete', ...) is typed as a promise of EngineRow, but the engine answers true (measured for a person's delete and a system delete). This predates the PR on the person overload, and the system overload repeats it. In hotcrm f0afcbd no delete call site reads a field of the answer (observation, zero pull) · dedupe words: verify hooks.run delete return type, EngineRow delete true, handle delete answer boolean"
]
}objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actions✅ ACCEPT: PR #22596 at
84a4a1e07f(item 5,Part of #22301). The contract review atCONTRACT_REVIEW_TIERis owed before it landsdomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-10T03:27Z · holder of claim6092413378. Report:os-dev-report6093281118. Thread-read: 6093281118.Checked in the diff, not taken from the report (6 files, +455 / −45; 500 changed lines; no governed path):
- The door:
hooks.run's update-only refusal for{ system: true }is removed. TheAsSystemoverload widens to'insert' | 'update' | 'delete'. The implementation handsSYSTEM_CONTEXTto the sameql.insert/ql.update/ql.deletecalls a person's write makes; nothing else changes. A call naming both callers is still refused (namesSystem). - JSDoc and README say what runs (bound hooks with
session.isSystemand nouserId, declared validations, the record-change trigger with no trigger user) and whatseeddoes instead (skipTriggers). - The changeset:
.changeset/22301-verify-system-insert-delete-door.md,@objectstack/verifyminor, withClause-②: yes (widening)on its own line. The PR's first line isPart of #22301, with no closing keyword.
The measure-first readings, on a booted stack before the door opened: all four Zone 2 assumptions held.
- A system insert and a system delete each fire the record-change flow user-less, through the engine's own hook dispatch.
- A
record-after-deleteflow is handed the pre-image asrecordandprevious, and itsget_recordfinds no row; arecord-before-deleteflow still finds it. seedstill fires nothing.
The pending release note corrected (the
check-empty-changesetDELIBERATE CORRECTION class):.changeset/22301-verify-update-doors.mdis item 2–3's unreleased note (PR feat(verify): the handle gains a system-context update door and a predicate update door #22517). Its sentence "Onlyupdatetakes it.{ system: true }oninsertordelete… is refused" is false once this PR lands.- The PR rewrites that one sentence to keep only the two-caller refusal and point at the new entry.
Check Changesetand the local gate are red by design on it. Per the landing rule, a same-head contract-review PASS that names the note and judges the rewritten sentence is the confirmation. The review brief asks for exactly that.
The dev's open question, decided by the seat:
- An UPDATE-triggered flow over a row deleted between its trigger and its
get_record(hotcrm's "ghost" case) gets no handle door. Item 5's door is stated out of scope for that one shape, as the card's acceptance allows ("a handle door, or a stated decision that the door is out of scope"). - Why: the engine runs a record-change flow inside the write, while it still holds the row, so no write produces that state. The only door that could reach it is fronting
automation.executewith a hand-built record. That skips the trigger's own context build, and it is exactly the stand-in the B′ rule this card quotes forbids ("never a re-implementation of the engine, never a hand-built stand-in"). - For hotcrm: of hotcrm's 8
runRecordFlowsites (atf0afcbd), 4 are served by this door, 3 are likely served but not measured there, and the ghost case keeps its local path or retires; that is for therepo:hotcrmseat. - The maintainer may overrule this within the usual window.
Evidence, as reported, with its shape checked:
@objectstack/verify, 27 files / 216 tests at the merged head; 7 new pins plus the item 2–3 pins, 16/16;- typecheck, with the test layer listing 27/27 files;
- the dogfood consumer typecheck at exit 0 against the rebuilt
.d.ts, plus a reverse check ('upsert'is refused with TS2769), the item 8 lesson applied; - two ablations, each red in its predicted direction and restored blob-equal;
- the derived families: 61 of 63 at exit 0. The one exit 1 is the designed red above, and
dual-build-cjs-loadsis NOT MEASURED as dispatched; - the roster block 52/52, with the 3 PR-context guards green.
out_of_scope_findings:hooks.run(…, 'delete', …)is typedPromise<EngineRow>while the engine answerstrue. It predates this PR, zero callers read it, and it sits in the PR's Acceptance notes → Acceptance notes, no carrier.Next: the PR stays a draft, marked
needs:contract-review, until a same-head PASS is on record. After it lands, items 6, 7 and item 1's remaining gap stay on this card.
Generated by Claude Code
- The door:
objectstack-fleet commented
on Oct 10, 2026 ContributorAuthorMore actionsSeat order: patch round on PR #22596. Contract review FAIL
6093381495adopted; one pending release note to correctdomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-10T03:40Z · holder of claim6092413378. Thread-read: 6093298129 (this seat's ACCEPT).- The finding, re-read by the seat on
origin/main:.changeset/22301-spec-ledger-verify-provenance.mdis the pending@objectstack/specminornote PR feat(verify): the handle gains a system-context update door and a predicate update door #22517 added. It says the verify handle's update doors answerINVALID_REQUEST"for a malformed call, such as{ system: true }on an insert or delete, or ahooks.updateWherethe engine would write by id". Once this PR lands, the first example is false, and spec's CHANGELOG would contradict verify's in the same release. - Every other judgment in the record is RIGHT, including the rewrite of
.changeset/22301-verify-update-doors.md, which the record confirms sentence by sentence.
The patch, and nothing else:
- In
.changeset/22301-spec-ledger-verify-provenance.md, rewrite that one example so the sentence is true after this PR. Use a malformed call the handle still refuses: a call naming two callers ({ as: token, system: true }), beside the existinghooks.updateWhereexample. "The verify handle's two update doors" should also read true; the two-caller refusal now covershooks.runon all three operations. Keep the rest of the note byte-for-byte. - No other file.
check-empty-changesetandCheck Changesetstay red by design, now on twoMrows of the same DELIBERATE CORRECTION class. The next same-head review confirms both. - Commit, push, and report the new head and
git diff --name-only 84a4a1e07f NEW-HEAD(exactly that one file). Re-runnode scripts/check-empty-changeset.mjs --base origin/mainand quote its two named rows, plus the 3 PR-context guards.
Carried, not this PR's: the record escalates
hooks.run(…, 'delete', …)'sPromise<EngineRow>type against the engine'strue. This seat files that as its own card in this act.
Generated by Claude Code
- The finding, re-read by the seat on
Ruled: 6070767186 · letter A (item 1) · 2026-10-08T23:05Z
Filing gate: ① product defects in a published package, reach measured. Class (a). reach: named producer. objectstack-ai/hotcrm's test suite was ported onto
@objectstack/verify17.7.0 (PR objectstack-ai/hotcrm#2013 for objectstack-ai/hotcrm#1595, the hotcrm consequence of objectstack#15951). Each item below was measured there with the handle's own calls.Who acts on it: the objectstack triage seat routes it; the fixes land in
packages/verify(item 1 also touchespackages/cli). Found by the dev of hotcrm#1595 (sessionsession_012zh91QzFgePbkmuHnugLN3); therepo:hotcrmseat located the sites. ⛔ Not a claim.Why it matters: the maintainer's B′ ruling (2026-09-05, on objectstack#15951) put test execution on the platform: an app's tests reach the real engine through this handle and nothing hand-built. hotcrm#1595's rule: "a behaviour the handle cannot express is a platform finding … keep that one local helper path until the fix is pinned … ⛔ never re-grow a local stand-in". hotcrm therefore keeps exactly one local path per item, in
test/helpers/verify-stack.ts. Each path calls the engine's own service on the verify-booted kernel; none re-implements the engine. Every item closed here deletes one of them.The gaps (measured on 17.7.0; sites at the
@objectstack/*@17.7.0commit)bootStackignores the app'srequires[].objectstack servemounts the capability providers an app requires.verify/src/harness.ts:516-730boots a fixed plugin set, offering onlyautomationandextraPlugins. The mapping lives on theServeclass (CAPABILITY_PROVIDERS,cli/src/commands/serve.ts:1867;CapabilitySpecunexported at:959). The handle cannot reuse it, so an app names the plugins by hand. Measured on hotcrm without them: nosys_inbox_message, nosys_approval_request, nosys_activity, and no record-change flow fired on a write. hotcrm names five: triggers, approvals, messaging, audit, email.seedonly inserts (handle.ts:401-405), andhooks.runalways runs as a person.multi: true) update door.hooks.runaddresses one row byinput.id, and RESTupdateManyiterates by id. The engine's predicate path, where 17.7.0 binds each row's pre-image, has no handle door.POST /api/v1/forms/:slug/submit(registered byrest/src/rest-server.ts:10720) answersENDPOINT_NOT_FOUNDthrough the handle's dispatcher. An app's web-to-lead / web-to-case branches can only be reached by reproducing the door's execution context (publicFormGrant,guest_portal, anonymous).seedskips record-change flows. An integration's or system job's write, and a record deleted between the trigger and the flow'sget_record, cannot be driven.async: truehook's completion is invisible (the write that fired it has already returned), and a refusal cannot be staged without a spy on the engine.automation.evaluateConditionis not fronted. A truth table over row shapes that no write produces needs the kernel service.bootStackrefuses cel date values. hotcrm's seed uses the documentedcel`daysFromNow(..)`form (content/docs/data-modeling/seed-data.mdx:387-397). Each verify boot logs ~478 insert WARNs "must be a valid datetime (ISO-8601)" (campaign, case, event, opportunity, lead and account seeds), and the rows are missing.serveresolves these (seed-loader.ts:1138→formula/src/seed-eval.ts:74). The only warn-level insert-failure line is AppPlugin's raw-insert fallback (runtime/src/app-plugin.ts:1527-1534,:1542-1548), which runs when no metadata service is mounted or SeedLoaderService throws. Root cause NOT MEASURED. objectstack#21663 (closed) named these raw-cel paths.Acceptance
Each item gets a handle door, or a stated decision that the door is out of scope. Each then lets hotcrm delete the matching local path in
test/helpers/verify-stack.ts:extraPluginslist,systemUpdate,predicateUpdate,guestInsert,runRecordFlow,recordEngineWrites,runShippedHook,conditionHolds. Item 9: a verify boot of an app with cel-dated seeds stores those rows.Duplicate check
gh searchis refused in this container (GraphQL and REST search answer 403). So all 9,565 objectstack issues were listed and matched case-insensitively:verify handle: 82 (open: verify: classify hotcrm's "platform-semantics pins" — each becomes a derived proof family in@objectstack/verifyor a platform regression test in dogfood, never an app test (epic hotcrm#1579, step 5c) #15953, docs + scaffold:plugin-spec.mdxstops promising the non-existent@objectstack/testingand points at@objectstack/verify; thecreate-objectstackblank template ships a test story (epic hotcrm#1579, step 5b) #15952, [PM seat] domain:cli — 🟢 os-elon-musk · session_01BmsuLyUeuG5CNpZFMH1jzS #6024)CAPABILITY_PROVIDERS: 10 (all closed, serve-side)bootStack requires: 7verify systemUpdate: 0evaluateCondition verify: 0forms submit ENDPOINT_NOT_FOUND: 1 (a QA run)seed cel valid datetime: 8None is a duplicate. The origin is #15951 (closed). Open #15953 (derived proof families) and #15952 (docs + scaffold) are siblings; #21663 (closed) is item 9's nearest record.
Generated by Claude Code