You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
rest: a write refused by an unevaluable hook condition answers a generic 500 INTERNAL_ERROR instead of a coded refusal (#24619 row b) #24662
Filing gate ④: a per-lane split of roll-up #24619 (row b). That card's triage (6272616654) says to split it on pickup. domain:engine seat 1 claimed row (a) only (6277262398) and pointed rows (b) and (c) back to triage (#60156277316794). Each row is ①. Filed by the triage seat (seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U. ⛔ Not a claim. Reader who acts: the domain:cli seat (packages/rest).
Answer:500 {"error":"Internal server error","code":"INTERNAL_ERROR"}. The server logs [REST] Unhandled error: HookConditionError: … — operation aborted. It reproduced 3 times over two fresh boots.
What holds: fail-closed. The row is not written.
Expected: a deliberate, coded refusal, not an unhandled internal error.
Fresh read (origin/maincc95f5e63e)
HookConditionError is declared at packages/objectql/src/hook-wrappers.ts:200 and exported from core.ts:83. Nothing under packages/rest/src names it, so it reaches the generic 500.
⛔ The wire code is a ledger decision, not a property.hook-wrappers.ts:187–199: ADR-0112 makes error.code a CLOSED vocabulary (StandardErrorCode ∪ ERROR_CODE_LEDGER, in packages/spec/src/api/). A .code added on the class would mint an unregistered wire code by side effect. So the fix is one of two:
map it to an existing StandardErrorCode in packages/rest's error mapping (this lane);
or register a ledger code, which is a packages/spec row (domain:spec). It goes serial or through the cross-domain path, with the file surface declared in the claim.
No HOOK_* code in packages/spec/src/api names an unevaluable condition today.
Pins: the card's request answers the chosen status and code, and the row is still not written.
Dedupe
#24619's search covers this row: "hook condition cannot be evaluated HookConditionError returns 500 INTERNAL_ERROR unhandled error", 11 hits, closed included. The nearest are #22856 (closed, the after* onError log case) and #24561 (the /batch hook-refusal envelope, a different door and error class). None is this one.
Claim: PM loop round 1 · domain:cli seat 2 · p2 · 2026-10-19T23:14Z
Session: session_01LmjU2x1faLZ39DVTFyVca6
Account: os-justin (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-24662-hook-condition-coded-refusal
Worktree: objectstack-issue-24662
Domain: domain:cli
Seat: domain:cli#2 (seat post #22648)
File surface (read on origin/main3a931fca1; line numbers move; stop on a breach and explain it in the report):
The error classification that turns a thrown HookConditionError (packages/objectql/src/hook-wrappers.ts:200, exported from core.ts:83) into a response. It now lives in packages/types/src/data-error-classification.ts (mapDataError), and packages/rest/src/error-response.ts re-exports it and resolves and emits from it. Today nothing names the class, so it reaches the generic 500 INTERNAL_ERROR and the [REST] Unhandled error line.
Every door that answers the card's write is measured on both transports: the REST plugin's data door and the runtime dispatcher's twin. The same classification serves both, or each gets the same answer.
Pins: the card's request answers the chosen status and error.code in the ADR-0112 envelope, the row is still not written, and no [REST] Unhandled error line is logged. A sibling control covers a hook that refuses on purpose, whose answer is unchanged. Each fixed door gets an ablation. Changesets: patch on each package whose shipped code moves.
⛔ Hold-offs:
packages/spec/**, which includes registering a new ledger code. If no existing StandardErrorCode fits, stop and report it with options.
Every other error class's answer.
Container & model: M (a judgment on the code choice, two transports), mode:subagent, model: default tier (dispatch-gates.mjs --tier: "no path-derived mandate")
Clause-②: no
Basis for the Clause-② line: the write is refused before and after. Only the refusal's status and code move, onto a member of the published StandardErrorCode catalog. No accept set moves, and no code is added. A new ledger code would make this yes, and it is out of this dispatch.
Responsibility: this lane's error classification (packages/types, packages/rest) answers an authored hook's unevaluable condition as an unhandled server fault. The platform path that covers it is fail-closed: the row is not written. It reaches every API caller whose write meets such a condition, and an AI client cannot tell that answer from a crash.
Thread-read: none
Serial constraints cleared:
os-dev-report
{
"issue": 24662,
"status": "done",
"branch": "claude/issue-24662-hook-condition-coded-refusal",
"pr": "#24714",
"session": "session_01LmjU2x1faLZ39DVTFyVca6 (mode:subagent, the parent PM's id, the commits' Claude-Session line)",
"premise_still_valid": true,
"summary": "Premise reproduced on origin/main eadea57 with the card's hook driven through a real engine and the engine's own bindHooksToEngine. The REST data door answered 500 INTERNAL_ERROR with a [REST] Unhandled error line, and so did createMany. On the dispatcher /data door the throw left dispatch(), and the Hono catch-all's declaredEnvelopeForThrow declined it, so the answer was 500 INTERNAL_ERROR with the hook's message. A /batch row answered INTERNAL_ERROR with a withheld message. The row was absent each time. One recogniser in @objectstack/types (hook-condition-refusal.ts, matched by name 'HookConditionError' plus reason 'unevaluable', not exported from the index) answers 400 and standardErrorCodeForHttpStatus(400) = VALIDATION_ERROR. Two rules read it. resolveThrownHttpError treats it as a declaration by shape, both status and code, which serves the dispatcher exits, both Hono doors and the batch rows. structuredCodeAnswer has a new arm beside its VALIDATION_FAILED precedent, which serves the REST single-record and bulk doors. The code choice follows the nearest landed precedent: a validation rule whose condition cannot be evaluated answers 400 on the same door, and its sentence comes from the same cel-fault.ts builder. VALIDATION_FAILED was not used because its per-field fields[] contract does not fit a hook gate. The branch test answers no: no consumer branches on the finer fact (objectui cd4623d: 0 production reads of constraint.reason 'unevaluable'). So no new code, no ledger row, and Clause-② stays no. The log: no REST line, because isDeclaredClientRefusal reads the declaration off resolveThrownHttpError, following AGENTS.md's 'a failure handed to the CALLER is not a degradation'. reason 'uncompilable' keeps its sanitised 500 and log line, pinned as a control. The pin sweep flipped three dogfood assertions (500 INTERNAL_ERROR became 400 VALIDATION_ERROR) and the checklist item records-forms.object-hook-lifecycle acceptance[8] (revision 7), and added one sentence to content/docs/automation/hooks.mdx. Nothing under packages/objectql or packages/spec was touched.",
"tests": "Head 910352e. types: vitest local 28 files / 764 passed, typecheck exit 0 (at 3ed86f1; the later commit is a rest test file only). rest: pnpm test (local) 301 files / 6099 passed / 326 skipped (at 3ed86f1); typecheck incl. check:test-typecheck exit 0; repo-project door-parity + sandbox-arm-message 2 files / 156 passed; the e2e pin rest-hook-condition-unevaluable-refusal.test.ts 5/5 at 910352e. runtime: data-hook-condition-refusal.test.ts plus five data-door/error-envelope files, 6 files / 108 passed; repo error-envelope.conformance 53 passed; typecheck incl. check:test-typecheck exit 0. metadata-protocol: 6 batch-row files / 94 passed. core: 4 import-runner files / 111 passed. plugin-hono-server: 34 files / 422 passed. hono adapter: 11 files / 215 passed. Dogfood, once on the final head: hook-after-condition-rollback.dogfood.test.ts 5/5 with the flipped pins; dogfood typecheck exit 0. Ablation, one leg, run after the fix was committed at 3ed86f1. ablation-replace.mjs WRAP changed the anchor name 'HookConditionError' to 'HookConditionError_ABLATED': anchor 1 to 0, blob 6099c6874149 to be145e442da8. types was rebuilt and ablation-dist-preflight (present) exited 0. Mutated leg: types 3 failed / 2 passed; rest e2e 2 failed ('expected 500 to be 400') / 2 controls passed; parity 1 failed / 65 passed; runtime 1 failed (declaredEnvelopeForThrow answered undefined) / 2 controls passed. Restore: blob == HEAD 6099c6874149, git diff HEAD empty, marker count 0. Restored leg: rebuild, preflight --absent exit 0 on a clean tree; types 5/5, rest 4/4, parity 66/66, runtime 3/3. The after-insert e2e case was added after the ablation and was not ablated on its own; it reads the same arm.",
"gates": "Local, at 910352e, after a full turbo build (76 tasks, 75 cached): node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 96 commands, and all 96 exited 0 (exit codes captured before any pipe). --ran reads '96 derived famil(ies) accounted for — 96 run, 0 NOT-MEASURED'. An earlier run at 3ed86f1, before the full build, had 2 families at exit 3 (check:skill-examples and check:dual-build-cjs-loads, PREREQUISITE NOT MET: dist missing); both exited 0 on the rerun. check-platform-checklist (node) exit 0. pnpm lint (eslint . --no-inline-config, whole repo) LINT_EXIT=0 at 910352e. CI on PR #24714 head 910352e, read once right after creation: 'No other open PR may claim the same issue' success, 'Packed-tarball smoke (opt-in)' skipped; the 22 others in_progress, among them Lint · ESLint, Type Check · workspace, Check Changeset, Governed Surface Queue Guard and 'The card this PR closes must claim this branch'. Test Core and Build Core had not yet appeared. NOT MEASURED: CI conclusions, because the report is not deferred for CI.",
"mcp_calls": "0",
"api_writes": "3 REST writes executed as objectstack-fleet[bot] through 2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches x2, session token): POST /repos/objectstack-ai/objectstack/pulls (draft #24714), POST /repos//issues/24714/assignees (os-justin), POST /repos//issues/24662/comments (this report). Plus 3 git pushes of the branch (the empty probe at eadea57, then 3ed86f1 and 910352e). These are not REST writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none — noted, not filed (PR Acceptance notes): a before* hook whose condition is unevaluable leaves no operator line at any layer, while its validation-rule sibling WARNs from its producer and an after* hook's fault is covered by the engine's warn-level 'Insert operation failed'. The producer side is packages/objectql (hook-wrappers.ts), held off by this dispatch. class: observation; reach: none filed",
"carrier: none — noted, not filed (PR Acceptance notes): on the dispatcher /data door (the @objectstack/hono catch-all), an uncompilable condition's undeclared 500 still relays its message verbatim, and that message quotes the condition source; the REST doors withhold it. This is the standing #5667 posture (undeclared 5xx kept legible), not reopened; measured only through declaredEnvelopeForThrow plus the fallback in an in-process rig. dedupe words: uncompilable hook condition source 500 message hono catch-all"
],
"deviations": [
"File surface widened inside packages/types, with the reason in the PR body. The runtime twin reads resolveThrownHttpError, not the classification, so thrown-http-error.ts carries the second reader and the recogniser is a new module, hook-condition-refusal.ts. packages/rest/src/error-response.ts needed no change. Zone 3's 'one arm in data-error-classification.ts so both transports get the same answer' is falsified as stated: the runtime door does not read that file.",
"The pin sweep reached three surfaces outside the claim's file list: packages/qa/dogfood/test/hook-after-condition-rollback.dogfood.test.ts (3 assertions flipped), docs/qa/platform-checklist/areas/records-forms.json (object-hook-lifecycle revision 7) and content/docs/automation/hooks.mdx (one sentence). None is a governed surface.",
"Narrowed: the full runtime and metadata-protocol suites were not run locally. Targeted files were run instead, as listed in tests, and CI's Test Core runs the full suites.",
"origin/main was not merged before the PR: 12 commits ahead; the one overlapping file (metadata-protocol protocol.ts, #24666) changes the exposure-gate read, not the batch-row seam.",
"Conflict with a harness reminder, noted rather than silently chosen: it asked for a model-named Co-Authored-By trailer and an emoji PR footer. AGENTS.md's model-free trailer pair and its session-URL footer form were used.",
"Two verify-lock attempts returned 99 (queue-timeout, 540s each), and one 10-minute foreground wait was moved to the background by the harness. That was waited on in-turn with tail --pid, and its WRAP trap restored the mutation."
],
"files_changed": "11 files, +665 / -15 vs base eadea57: .changeset/24662-hook-condition-coded-refusal.md (+12, @objectstack/types patch), content/docs/automation/hooks.mdx (+4/-1), docs/qa/platform-checklist/areas/records-forms.json (+9/-3), packages/qa/dogfood/test/hook-after-condition-rollback.dogfood.test.ts (+7/-6), packages/rest/src/error-response-structured-arm-door-parity.test.ts (+27/-1), packages/rest/src/rest-hook-condition-unevaluable-refusal.test.ts (+215), packages/runtime/src/domains/data-hook-condition-refusal.test.ts (+151), packages/types/src/data-error-classification.ts (+32), packages/types/src/hook-condition-refusal.test.ts (+88), packages/types/src/hook-condition-refusal.ts (+103), packages/types/src/thrown-http-error.ts (+17/-4)",
"line_budget": "665 + 15 = 680 changed lines, under the 3000 human-merge threshold (dispatch-gates reading at 3ed86f1: 656 lines; the after-insert case added 24). No skills/** or ratcheted ledger touched."
}
ACCEPT → PR #24714 comment 6281218192 · domain:cli seat 2 · session session_01LmjU2x1faLZ39DVTFyVca6 · 2026-10-20T01:32Z · head 910352e21. An unevaluable hook condition now answers 400 VALIDATION_ERROR at every data door (existing code, Clause-②: no). Landing is held while main-red #24700 is open, then waits on every check of the head.
What landed: an authored hook condition that compiled and then could not be evaluated on the record now answers 400 VALIDATION_ERROR at every data door (REST single-record and bulk, the dispatcher's /data, /batch rows), where it answered 500 INTERNAL_ERROR. The message names the hook and the fault, never the condition source or a record value. The row is still not written, uncompilable keeps its sanitised 500, and no error code is added.
Activity
objectstack-fleet commentedon Oct 19, 2026
Claim: PM loop round 1 ·
domain:cliseat 2 · p2 · 2026-10-19T23:14ZSession:
session_01LmjU2x1faLZ39DVTFyVca6Account:
os-justin(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24662-hook-condition-coded-refusalWorktree:
objectstack-issue-24662Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)File surface (read on
origin/main3a931fca1; line numbers move; stop on a breach and explain it in the report):HookConditionError(packages/objectql/src/hook-wrappers.ts:200, exported fromcore.ts:83) into a response. It now lives inpackages/types/src/data-error-classification.ts(mapDataError), andpackages/rest/src/error-response.tsre-exports it and resolves and emits from it. Today nothing names the class, so it reaches the generic500 INTERNAL_ERRORand the[REST] Unhandled errorline.error.codein the ADR-0112 envelope, the row is still not written, and no[REST] Unhandled errorline is logged. A sibling control covers a hook that refuses on purpose, whose answer is unchanged. Each fixed door gets an ablation. Changesets:patchon each package whose shipped code moves.packages/spec/**, which includes registering a new ledger code. If no existingStandardErrorCodefits, stop and report it with options.packages/objectql/**: the class itself, its fields and its message. PR fix(objectql): a runAs:'user' hook carries its user's email, so a current_user.email row policy admits it as it admits the user's own request #24674 has an open hunk inhook-wrappers.ts.Container & model:
M(a judgment on the code choice, two transports),mode:subagent,model: default tier(dispatch-gates.mjs --tier: "no path-derived mandate")Clause-②: no
Basis for the Clause-② line: the write is refused before and after. Only the refusal's status and code move, onto a member of the published
StandardErrorCodecatalog. No accept set moves, and no code is added. A new ledger code would make thisyes, and it is out of this dispatch.Responsibility: this lane's error classification (
packages/types,packages/rest) answers an authored hook's unevaluable condition as an unhandled server fault. The platform path that covers it is fail-closed: the row is not written. It reaches every API caller whose write meets such a condition, and an AI client cannot tell that answer from a crash.Thread-read: none
Serial constraints cleared:
data-error-classification.tsorerror-response.ts, and nopm:dispatchedclaim names them. Read in this act. PR perf(rest): GET /data/OBJECT no longer computes metadata diagnostics; the exposure gate reads getMetaItemForExecution #24666 (rest: every GET /api/v1/data/OBJECT still runs a full zod safeParse of the object's definition (the API-exposure gate's by-name read is decorated with diagnostics) — 11.8% of a HotCRM read's CPU #24535) editsrest-server.ts, which is another file.hook-wrappers.ts, which is held off here.dependenciescan be set only at create —PATCH /api/v1/packages/:idpersists only name / description / version, so a save refused with "declare a dependency" has no remedy short of recreating the package #24670 and Flaky on Test Core (6/6):packages/runtimeshare-links-refusal-order.test.ts› dispatcher twin › "[#23372] email audience: the refusal is the one an unknown token and a password-less email link answer" times out at vitest's 5000 ms default #24633, are disjoint.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{
"issue": 24662,
"status": "done",
"branch": "claude/issue-24662-hook-condition-coded-refusal",
"pr": "#24714",
"session": "session_01LmjU2x1faLZ39DVTFyVca6 (mode:subagent, the parent PM's id, the commits' Claude-Session line)",
"premise_still_valid": true,
"summary": "Premise reproduced on origin/main eadea57 with the card's hook driven through a real engine and the engine's own bindHooksToEngine. The REST data door answered 500 INTERNAL_ERROR with a [REST] Unhandled error line, and so did createMany. On the dispatcher /data door the throw left dispatch(), and the Hono catch-all's declaredEnvelopeForThrow declined it, so the answer was 500 INTERNAL_ERROR with the hook's message. A /batch row answered INTERNAL_ERROR with a withheld message. The row was absent each time. One recogniser in @objectstack/types (hook-condition-refusal.ts, matched by name 'HookConditionError' plus reason 'unevaluable', not exported from the index) answers 400 and standardErrorCodeForHttpStatus(400) = VALIDATION_ERROR. Two rules read it. resolveThrownHttpError treats it as a declaration by shape, both status and code, which serves the dispatcher exits, both Hono doors and the batch rows. structuredCodeAnswer has a new arm beside its VALIDATION_FAILED precedent, which serves the REST single-record and bulk doors. The code choice follows the nearest landed precedent: a validation rule whose condition cannot be evaluated answers 400 on the same door, and its sentence comes from the same cel-fault.ts builder. VALIDATION_FAILED was not used because its per-field fields[] contract does not fit a hook gate. The branch test answers no: no consumer branches on the finer fact (objectui cd4623d: 0 production reads of constraint.reason 'unevaluable'). So no new code, no ledger row, and Clause-② stays no. The log: no REST line, because isDeclaredClientRefusal reads the declaration off resolveThrownHttpError, following AGENTS.md's 'a failure handed to the CALLER is not a degradation'. reason 'uncompilable' keeps its sanitised 500 and log line, pinned as a control. The pin sweep flipped three dogfood assertions (500 INTERNAL_ERROR became 400 VALIDATION_ERROR) and the checklist item records-forms.object-hook-lifecycle acceptance[8] (revision 7), and added one sentence to content/docs/automation/hooks.mdx. Nothing under packages/objectql or packages/spec was touched.",
"tests": "Head 910352e. types: vitest local 28 files / 764 passed, typecheck exit 0 (at 3ed86f1; the later commit is a rest test file only). rest: pnpm test (local) 301 files / 6099 passed / 326 skipped (at 3ed86f1); typecheck incl. check:test-typecheck exit 0; repo-project door-parity + sandbox-arm-message 2 files / 156 passed; the e2e pin rest-hook-condition-unevaluable-refusal.test.ts 5/5 at 910352e. runtime: data-hook-condition-refusal.test.ts plus five data-door/error-envelope files, 6 files / 108 passed; repo error-envelope.conformance 53 passed; typecheck incl. check:test-typecheck exit 0. metadata-protocol: 6 batch-row files / 94 passed. core: 4 import-runner files / 111 passed. plugin-hono-server: 34 files / 422 passed. hono adapter: 11 files / 215 passed. Dogfood, once on the final head: hook-after-condition-rollback.dogfood.test.ts 5/5 with the flipped pins; dogfood typecheck exit 0. Ablation, one leg, run after the fix was committed at 3ed86f1. ablation-replace.mjs WRAP changed the anchor name 'HookConditionError' to 'HookConditionError_ABLATED': anchor 1 to 0, blob 6099c6874149 to be145e442da8. types was rebuilt and ablation-dist-preflight (present) exited 0. Mutated leg: types 3 failed / 2 passed; rest e2e 2 failed ('expected 500 to be 400') / 2 controls passed; parity 1 failed / 65 passed; runtime 1 failed (declaredEnvelopeForThrow answered undefined) / 2 controls passed. Restore: blob == HEAD 6099c6874149, git diff HEAD empty, marker count 0. Restored leg: rebuild, preflight --absent exit 0 on a clean tree; types 5/5, rest 4/4, parity 66/66, runtime 3/3. The after-insert e2e case was added after the ablation and was not ablated on its own; it reads the same arm.",
"gates": "Local, at 910352e, after a full turbo build (76 tasks, 75 cached): node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 96 commands, and all 96 exited 0 (exit codes captured before any pipe). --ran reads '96 derived famil(ies) accounted for — 96 run, 0 NOT-MEASURED'. An earlier run at 3ed86f1, before the full build, had 2 families at exit 3 (check:skill-examples and check:dual-build-cjs-loads, PREREQUISITE NOT MET: dist missing); both exited 0 on the rerun. check-platform-checklist (node) exit 0. pnpm lint (eslint . --no-inline-config, whole repo) LINT_EXIT=0 at 910352e. CI on PR #24714 head 910352e, read once right after creation: 'No other open PR may claim the same issue' success, 'Packed-tarball smoke (opt-in)' skipped; the 22 others in_progress, among them Lint · ESLint, Type Check · workspace, Check Changeset, Governed Surface Queue Guard and 'The card this PR closes must claim this branch'. Test Core and Build Core had not yet appeared. NOT MEASURED: CI conclusions, because the report is not deferred for CI.",
"mcp_calls": "0",
"api_writes": "3 REST writes executed as objectstack-fleet[bot] through 2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches x2, session token): POST /repos/objectstack-ai/objectstack/pulls (draft #24714), POST /repos//issues/24714/assignees (os-justin), POST /repos//issues/24662/comments (this report). Plus 3 git pushes of the branch (the empty probe at eadea57, then 3ed86f1 and 910352e). These are not REST writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none — noted, not filed (PR Acceptance notes): a before* hook whose condition is unevaluable leaves no operator line at any layer, while its validation-rule sibling WARNs from its producer and an after* hook's fault is covered by the engine's warn-level 'Insert operation failed'. The producer side is packages/objectql (hook-wrappers.ts), held off by this dispatch. class: observation; reach: none filed",
"carrier: none — noted, not filed (PR Acceptance notes): on the dispatcher /data door (the @objectstack/hono catch-all), an uncompilable condition's undeclared 500 still relays its message verbatim, and that message quotes the condition source; the REST doors withhold it. This is the standing #5667 posture (undeclared 5xx kept legible), not reopened; measured only through declaredEnvelopeForThrow plus the fallback in an in-process rig. dedupe words: uncompilable hook condition source 500 message hono catch-all"
],
"deviations": [
"File surface widened inside packages/types, with the reason in the PR body. The runtime twin reads resolveThrownHttpError, not the classification, so thrown-http-error.ts carries the second reader and the recogniser is a new module, hook-condition-refusal.ts. packages/rest/src/error-response.ts needed no change. Zone 3's 'one arm in data-error-classification.ts so both transports get the same answer' is falsified as stated: the runtime door does not read that file.",
"The pin sweep reached three surfaces outside the claim's file list: packages/qa/dogfood/test/hook-after-condition-rollback.dogfood.test.ts (3 assertions flipped), docs/qa/platform-checklist/areas/records-forms.json (object-hook-lifecycle revision 7) and content/docs/automation/hooks.mdx (one sentence). None is a governed surface.",
"Narrowed: the full runtime and metadata-protocol suites were not run locally. Targeted files were run instead, as listed in tests, and CI's Test Core runs the full suites.",
"origin/main was not merged before the PR: 12 commits ahead; the one overlapping file (metadata-protocol protocol.ts, #24666) changes the exposure-gate read, not the batch-row seam.",
"Conflict with a harness reminder, noted rather than silently chosen: it asked for a model-named Co-Authored-By trailer and an emoji PR footer. AGENTS.md's model-free trailer pair and its session-URL footer form were used.",
"Two verify-lock attempts returned 99 (queue-timeout, 540s each), and one 10-minute foreground wait was moved to the background by the harness. That was waited on in-turn with tail --pid, and its WRAP trap restored the mutation."
],
"files_changed": "11 files, +665 / -15 vs base eadea57: .changeset/24662-hook-condition-coded-refusal.md (+12, @objectstack/types patch), content/docs/automation/hooks.mdx (+4/-1), docs/qa/platform-checklist/areas/records-forms.json (+9/-3), packages/qa/dogfood/test/hook-after-condition-rollback.dogfood.test.ts (+7/-6), packages/rest/src/error-response-structured-arm-door-parity.test.ts (+27/-1), packages/rest/src/rest-hook-condition-unevaluable-refusal.test.ts (+215), packages/runtime/src/domains/data-hook-condition-refusal.test.ts (+151), packages/types/src/data-error-classification.ts (+32), packages/types/src/hook-condition-refusal.test.ts (+88), packages/types/src/hook-condition-refusal.ts (+103), packages/types/src/thrown-http-error.ts (+17/-4)",
"line_budget": "665 + 15 = 680 changed lines, under the 3000 human-merge threshold (dispatch-gates reading at 3ed86f1: 656 lines; the after-insert case added 24). No skills/** or ratcheted ledger touched."
}
Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
ACCEPT → PR #24714 comment
6281218192·domain:cliseat 2 · sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-20T01:32Z · head910352e21. An unevaluable hook condition now answers400 VALIDATION_ERRORat every data door (existing code,Clause-②: no). Landing is held while main-red #24700 is open, then waits on every check of the head.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Landed: PR #24714 →
014863d5d(Fixes #24662)domain:cliseat 2 ·os-justin· sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-20T03:26Zadded_to_merge_queue02:54Z)origin/main014863d5dis on it, with a single parent (squash). 11 files, +665 / −15, matching the ACCEPTed head910352e21gh-readonly-queue/main/*pr-24714*head remainscompletedby the PR'sFixes. In the stroke after this comment,pm:dispatchedcomes off6279442235→ report6281181277→ ACCEPT6281218192→ pointer6281225759.400 VALIDATION_ERRORat every data door (REST single-record and bulk, the dispatcher's/data,/batchrows), where it answered500 INTERNAL_ERROR. The message names the hook and the fault, never the condition source or a record value. The row is still not written,uncompilablekeeps its sanitised500, and no error code is added.Generated by Claude Code