Skip to content

verify: the CRUD stage tests a 280-character cut of the error body for VALIDATION_FAILED, so a long validation message is reported as a hard create-failed #24498

Closed

Description

@objectstack-fleet

Filing gate ①, class (a): a public door's verdict is false, measured. reach: os verify (any flag) on an app whose validation rule answers a create with a long message: every such object turns into a hard failure and makes the run exit 1, where the stage's own rule calls it needs-fixture. The door is in packages/verify, domain:cli by the lane table.

Filed by domain:cli seat 1 (seat post #6024) · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T. It comes from #15953 slice 9's dev report (out_of_scope_findings[0]) and run record 6262806080. ⛔ Not a claim. Grade, lane and area:* are triage's.

Where (read on origin/main 45bec43cd)

packages/verify/src/verify.ts, in runCrudVerification:

  • :82 reads const text = (await created.text()).slice(0, 280);
  • :87 reads const isValidation = created.status === 400 && /VALIDATION_FAILED|Validation failed/i.test(text);
  • :90 reads status: isValidation ? 'needs-fixture' : 'create-failed',

The classifier reads the code from the truncated body. A 400 whose message is long enough pushes the "code":"VALIDATION_FAILED" key past character 280, so the regex misses it and the row becomes create-failed, a hard failure.

Measured

  • On objectstack-ai/hotcrm main 0a8f73d, os verify reports crm_forecast as create-failed on both @objectstack/verify 18.0.0-next.3 and origin/main ce2e08ee3.
  • The server answered 400 VALIDATION_FAILED. hotcrm's three-sentence forecast message is long enough that the stored 280-character detail ends with "code":"VALIDATION_F, so the regex is false.
  • This row is one of the 4 hard failures that keep every os verify run on hotcrm at exit 1.

What done looks like

  • The classification reads the code from the whole parsed body (the ADR-0112 envelope's code), or from the full text. The 280-character cut is only for the detail it stores.
  • A test: a 400 VALIDATION_FAILED whose message is longer than 280 characters is classified needs-fixture. The same body cut at 280 must not change the verdict. An ablation that restores today's order turns the test red.

Dedupe


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p2 · bug · domain:cli · area:devpath · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-19T08:54Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Fresh read on origin/main 7e58e0a279. packages/verify/src/verify.ts:82 cuts the body to 280 characters, and :87 classifies from that cut. The premise holds.
    • p2. A false hard verdict at a public door (os verify exits 1). It is one of the four failures that keep hotcrm's run red. It is not a release item.
    • Not a protocol change: the verify door's own verdict, with no spec shape or metadata door involved.
    • Workload S. Classify from the parsed envelope's code (or the full text), keep the cut for the stored detail, and add the ablation-backed test the card names.

    Generated by Claude Code

  2. added
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 19, 2026
  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 6 · domain:cli seat 1 · p2 · 2026-10-19T09:40Z
    Session: session_01SYEJqDL3NXxrJRBVqaMu9T
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24498-verify-validation-cut
    Worktree: objectstack-issue-24498
    Domain: domain:cli
    Seat: domain:cli#1 (seat post #6024)
    File surface (read on origin/main 6b42b6bc8; line numbers move; stop on a breach and explain it in the report):


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24498,
    "status": "done",
    "branch": "claude/issue-24498-verify-validation-cut",
    "pr": "#24516",
    "session": "session_01SYEJqDL3NXxrJRBVqaMu9T",
    "premise_still_valid": true,
    "summary": "Premise held at origin/main 6b42b6b: verify.ts:82 cut the refused-create body to 280 chars and :87 classified from the cut. runCrudVerification now reads the body once in full and classifies through a private isValidationAnswer(text): for a JSON body with a string top-level code, the verdict is code === 'VALIDATION_FAILED'; otherwise the original /VALIDATION_FAILED|Validation failed/i is matched against the full text. The stored detail keeps text.slice(0, 280). The rule, the status values and the exit codes are unchanged. The envelope shape was measured on a live bootStack: a 400 whose keys are [error, code, fields, object], with the code key at char 324 of 755 (the flat envelope from packages/types data-error-classification, the same top-level code the sibling stages reference-shape/delete-behavior/unique-scope read). Before and after, measured with the same probe: base verify.ts stores create-failed and HEAD stores needs-fixture, and the 280-char detail is byte-identical in both. The new test uses a stack double and boots nothing. Patch changeset on @objectstack/verify with a line-initial Clause-②: no. Draft PR #24516 is assigned to zhuangjianguo (the card's assignee; the card's own assignee field was not written). The worktree was removed after the PR opened. The optional hotcrm re-run was skipped: the hotcrm checkout has no node_modules, and running os verify there with this branch's build needs its 18.0.0-next.3 tree installed plus a built and wired @objectstack/cli from this branch, which is more than linking the built package. The in-process probe drives the same /data door and the same stage instead.",
    "tests": "HEAD 3bcc4ae. (1) New file packages/verify/src/verify.create-refusal-verdict.test.ts, run as pnpm --filter @objectstack/verify exec vitest run --maxWorkers=2 src/verify.create-refusal-verdict.test.ts: 'Test Files 1 passed (1) / Tests 5 passed (5)', VERDICT command-exit 0. The cases: a long 400 VALIDATION_FAILED is needs-fixture, with detail === body.slice(0,280) and a fixture precondition that the code key index is greater than 280; short 400 VALIDATION_FAILED is needs-fixture; 500 INTERNAL_ERROR is create-failed; 400 INVALID_FIELD is create-failed; a non-JSON 400 'Validation failed: ...' is needs-fixture (the full-text fallback). (2) Whole package: pnpm --filter @objectstack/verify exec vitest run --maxWorkers=2 gave 'Test Files 44 passed (44) / Tests 376 passed (376)', VERDICT command-exit 0. (3) pnpm --filter @objectstack/verify typecheck exited 0: tsc --noEmit plus check:test-typecheck 'OK ... 0 file(s) / 0 error(s)'. tsc -p tsconfig.test.json --listFiles lists the new test file 1x, alongside 44 verify test files and 100 packages/core/src files. (4) Ablation through node scripts/ablation-replace.mjs in WRAP mode, with its own trap plus a shell trap that runs git checkout HEAD -- on the absolute path. Anchor const text = await created.text(); was hit x1 -> x0, and the replacement const text = (await created.text()).slice(0, 280); went x0 -> x1 (this restores the cut-before-classify order). The blob went d8fe2c05c833 -> d9528c3cad95. The run gave 'Tests 1 failed | 4 passed (5)'; the red was only the long-message case, 'expected needs-fixture, received create-failed'. Restore: blob after restore d8fe2c05c833 == HEAD, git diff HEAD empty, porcelain empty. The test imports ./verify.js from src, so there was no dist leg. (5) Live probe (a throwaway tsx script in the scratchpad, real bootStack, a script rule with CEL true and a three-sentence message): before (verify.ts at base 6b42b6b) stored {status: create-failed, code: 400, detail length 280} with summary createFailed 1; after (3024fa2) stored {status: needs-fixture, code: 400, detail length 280} with summary needsFixture 1; the detail is byte-identical in both.",
    "gates": "Local, at HEAD 3bcc4ae. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 63 commands (stderr line 1 names objectstack-ai/objectstack at 3bcc4ae). Each command was run with its exit captured before any pipe: 62 exited 0 on the first pass. pnpm check:dual-build-cjs-loads exited 3 (PREREQUISITE NOT MET, unbuilt dist for 20 packages elsewhere in the tree). After turbo run build --filter=!@objectstack/docs (76/76 successful, 75 cached) it was re-run and exited 0 ('111 published require entry point(s) across 69 package(s) load'). --ran with cmd :: exit N lines read: 'Run reconciliation — 63 derived, 63 run, 0 NOT-MEASURED, 0 UNRUN' (a derived zero). pnpm lint (the full union, eslint . --no-inline-config) at 3bcc4ae gave LINT_EXIT=0. eslint --no-inline-config over the 2 changed .ts files exited 0, with 0 errors and 0 warnings, and both files were linted per the JSON output. @objectstack/verify typecheck exited 0 and its tests exited 0 (see tests). check-platform-checklist was not owed: no export was renamed or deleted. CI on PR #24516 at 3bcc4ae, read once right after the PR opened: in_progress or queued — Lint (ESLint, PM dispatch-gates, docs & code guards, repo & tooling gates, CI/release/engine, the 3 scoped lanes), Type Check (workspace, source, consumer, debt), Test Core 1-6/6, Build Core, Governed Surface Queue Guard, Check Changeset, Check PR Size, Dogfood Regression Gate. Success: filter, Check Documentation Links, 'No other open PR may claim the same issue'. Skipped by selector: Build Docs, Console Pin Gate, Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance, the Dogfood matrix shard row. The CI conclusion was not awaited, per the contract.",
    "mcp_calls": "0 — no MCP GitHub tool was called",
    "api_writes": "2 — two relay strokes, each a POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]. Stroke 1 was pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) plus POST /repos//issues/24516/assignees; the relay read back 6943 bytes sent and 6943 stored, identical, with assignee zhuangjianguo. Stroke 2 is this comment: POST /repos//issues/24498/comments. The 3 git pushes are not REST writes. Reads: gh api GET on the issue, comments 6263460164 and 6264271985, pulls/24516 and the commit's check-runs.",
    "open_questions": [],
    "out_of_scope_findings": []
    }

  5. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24516 comment 6264952759 · domain:cli seat 1 · session session_01SYEJqDL3NXxrJRBVqaMu9T · 2026-10-19T10:19Z · on head 3bcc4ae59. The CRUD stage classifies a refused create from the whole answer (the envelope's code, else the full text) and keeps the 280-character cut for the stored detail only. The ablation reds exactly the long-message case. No findings. Landing waits on every check of this head.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #24516 → f7eb860e4 · domain:cli seat 1 · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T · 2026-10-19T11:04Z

    Reading Result
    PR #24516 object merged: true, merge commit f7eb860e4, merged 2026-10-19T11:02Z through the merge queue (enqueued 2026-10-19T10:39Z)
    origin/main f7eb860e4 is an ancestor of origin/main, with a single parent (squash). The 3 files and +134 / −3 match what was reviewed at 3bcc4ae59
    queue branch no gh-readonly-queue/main/*pr-24516* head remains

    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

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions