Skip to content

QA run · cli (FULL area) · 92f26f75 · 2026-08-11 · 4 PASS / 1 PARTIAL / 1 FAIL #7628

Description

@baozhoutao

Full cli area run of the checklist-test skill — all 6 items driven against real CLI invocations + a live showcase (opus subagent, isolated boot + file DB). Text-only per RUNNER.md.

Result: 4 PASS · 1 PARTIAL · 1 FAIL.

Environment — framework 92f26f75 (branch claude/platform-test-checklist-ocwugl) · vendored console 6314e87f · showcase app · isolated port + file DB.

✅ PASS — 4 items

  • dev-boot-contract (7/7 + both negatives) — health + ready + console all serve; --seed-admin does not overwrite an existing admin account on a second boot (old password still works, the new one 401s); all 5 DB-choice variants print the right resolved URL and the nothing-chosen default is a persistent project-anchored sqlite file (never memory://), verified on disk; --fresh creates and deletes its tempdir after exit (verified twice, plus a global sweep for leftovers); an occupied port auto-shifts and every printed URL uses the actual port (grepping the log for the requested port came back empty); a stale artifact warns with the newest-source filename and the fix line but still boots; a missing config exits 1 in ~2 s with a located remedy.
    Item text drift (not a defect): clause 2 names .objectstack/data/dev.db and resolveDefaultDevDbUrl, both superseded by the unified objectstack.db default. The load-bearing property holds; the item text needs a refresh.
  • migrate-plan-apply-json (7/7 + both negatives) — bare migrate plans without writing, proven physically (a sqlite_master dump before/after compared byte-equal, twice) rather than from the payload; the --json payload carries the declared keys; all five--json subcommands exit exactly 0 (no os migrate 成功时退出码是随机非零值(208/171/176/163/62…),--version / --help 却干净退出 0 #4873 duration-in-exit-slot leak — the format.exit-code pin was run, 4/4); destructive drops are skipped without --allow-destructive and applied with it (PRAGMA table_info proving both sides); apply is idempotent (in_sync on re-run); a busy DB refuses apply with exit 1 naming the holding pid while plan still succeeds with a warning; confirmation_required does not mutate (again proven by a physical dump).
    Cosmetic oddity, not filed: the summary prints "1 table(s) to create, 1 column(s) to add" immediately followed by "0 change(s): 0 safe, 0 needs-confirm, 0 destructive".
  • verify-verdict-exit-mapping (5/5 + both negatives) — every status is a member of the declared six-name union and the summary reconciles with a recomputed sum on both a clean and a staged-failing run; the exit-1 side was staged (a QA-only beforeInsert hook rewriting a field so written ≠ read-back) rather than skipped, closing the item's knownGap, and the human format agreed with the recomputed sum; a 400 VALIDATION_FAILED is classified needs-fixture and excluded from hardFailures while a 5xx would be a real failure; --rls adds the rls block and boots a separate stack, proven empirically by counting plugin-load lines (2 vs 1) rather than from a comment; OS_TENANCY_POSTURE=isolatedhard-fails with a located enterprise-package error instead of the 普查:plugin-auth 之外还有 6 处把被降级的 OS_MULTI_ORG_ENABLED 当「是不是多组织」在读 —— 只设 OS_TENANCY_POSTURE 的部署会静默走错分支 #5262 quiet single-org pass.
  • flag-command-error-ux (4/4 + both negatives) — unknown flag, invalid enum value (with the full allowed set enumerated), unknown top-level command and unknown topic subcommand all exit 2 with a located stderr message; the command body provably never ran (stdout empty, and the body markers captured from genuine runs of the same commands were absent); --help swept across the root plus all 30 declared variants — 31/31 exit 0 with exactly one USAGE block each, none inferred from a sibling.

🔴 FAIL — 1 item

scaffold-first-run — 4 of 6 published remote templates fail their very first npm run build

The blank template's full published first-run is clean end to end (scaffold → install → validate → build → boot → health 200 in 7 s → ready). The skills boundary is proven: --all --copy installs exactly the curated 11 (set-equality, zero diff) and repo-root discovery surfaces 11 with no internal skill leaking.

Reproduction rule

npx -y create-objectstack@latest canary-app -t todo --skip-skills --skip-install
cd canary-app && npm install && npm run build

Expected exit 0. Actual exit 2:

defineStack namespace-prefix validation failed (2 issues):
Object todo_label is missing the package namespace prefix.
Rename it to canary_app_todo_label (namespace = canary_app)

Reproduced on 4 independent templatestodo / compliance / content / contracts (2 / 4 / 5 / 3 issues respectively). procurement is blocked(environment) (codeload 503/403 in this sandbox).

Root cause (located). Published create-objectstack@16.1.0 rewrites namespace: in objectstack.config.ts to the sanitized project name but not the object-name literals, because it reads the template's original namespace from objectstack.manifest.json only — and a remote template's manifest is the template-registry document, which has no namespace key at all. The guard falls through and the rewrite is silently skipped. Verified on the generated tree: the config says namespace tpl_todo while the object literal still says name: 'todo_task'. This triggers for any project name whose sanitized namespace differs from the template's own — i.e. every real user, and CI's own canary-app.

⚠️ Already fixed at repo HEAD — do not re-file as a code bug. The residual action is a release, not a repair.

packages/create-objectstack/src/rewrite-identity.ts makes objectstack.config.ts the authority and self-verifies via findStaleNamespacePrefixes; its comment names this exact incident (#4902: "All five published remote templates … failed this way, and the nightly registry canary had been red on every one of them for weeks with nobody watching"). Pin run: rewrite-identity.test.ts10/10 pass.

But npm latest is still 16.1.0, so every new user who picks a non-blank template today gets a project that fails on its first build. Asks: (1) confirm the fix ships in 17.0.0, and (2) confirm the nightly registry canary goes green once it does.

🟡 PARTIAL — 1 item

build-own-contract — clause 4 is a clause scope gap, not a product defect

Passing: build/compile alias parity · the --json key contract · located per-path schema errors (not a bare "validation failed") · all failing author-time rules reported at once with where/message/hint/rule/path · build-vs-validate --json parity proven by computed set-equality on both the success and the failure envelope · advisory-vs-error separation.

Clause 4 is partial. Exit codes are clean for every --json invocation (0/1/1/1), but a config-load-time throw exits 2 on the human path (reproduced twice), because compile.ts's catch ends in this.error() and oclif's ExitError is 2 — the CliExitCode 0|1 type only narrows the emitJson/emitText slot. That is oclif's standard error exit, the same code cli.flag-command-error-ux asserts as correct, and not the #4873 duration-leak this clause exists to pin.

Checklist reconciliation needed (not a product bug): two items in this area disagree about exit code 2 — build-own-contract clause 4 treats it as outside the 0|1 union, flag-command-error-ux asserts it as the correct oclif error exit. The clause should be narrowed to the duration-leak it was written for.

Unverified side-observation, explicitly not filed: the runtime bundle filename hash differed across runs whose inputs were restored byte-for-byte, suggesting the bundle name may not be content-deterministic. Needs a dedicated reproduction before it means anything.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingqa-run

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions