Repository navigation
Commit 59441b6
docs(qa): automation recipes score the second packaged caller and the 503 store arm (#26802)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8DcJexQ1vAppgxsiiNUjjkf)_
Fixes #26622
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:`areas/automation.json` 新增区级配方
`qa-second-packaged-caller`(N1),并给已有配方 `qa-flow-status-doors` 加第 5
步故障臂(A4 的 503);两个条目 revision 各升一级(9 → 10、6 → 7)。
- 为什么改:两条子句在 18.2.0 两轮里都只能记 blocked(fixture):N1 要第二个「打包」调用方,A4 的 503
STORE_UNAVAILABLE 没有现成触发办法。
- 风险与回滚:只改 QA 台账一个 JSON 文件,不动产品代码;回滚即 revert 本 PR。
- 先看:`docs/qa/platform-checklist/areas/automation.json` 顶部 `fixtures`
块的新配方与 step 5,再看两个条目 history 的最新一行(含裁决)。
- 两分钟验证:`node scripts/check-platform-checklist.mjs`,预期 OK,且显示 7
个区级配方、7/7 被引用。
- 需要你做的:无,席位落地。
## What changes
- `docs/qa/platform-checklist/areas/automation.json` gains the
area-level recipe `qa-second-packaged-caller`, in the README's
"Area-level `fixtures`" shape: one `POST
/api/v1/marketplace/install-local` call carrying an inline manifest
whose one flow, `qasub_second_notify_caller`, calls
`showcase_notify_owner` as a subflow, a read-back step, and a mandatory
teardown.
- The existing recipe `qa-flow-status-doors` gains step 5, the fault arm
for the resume door's 503 `STORE_UNAVAILABLE` row: with a live paused
`showcase_reassign_wizard` run, `sys_automation_run` is renamed away in
the boot's telemetry database (`node:sqlite`, a second process) for one
resume, then renamed back. Its title, `why`, `provenance`, `requires`
and `teardown` say so.
- `automation.packaged-flow-subflow-disable-refusal` (revision 9 → 10)
opts in with `fixtures.provisioning.use` + `why`; `negative[1]` names
the recipe instead of `blocked(fixture)`; `steps[8]` drives the
several-callers leg; `knownGaps` gains its CLOSED-by-recipe line (the
engine-pin fallback kept); `source` cites the install-local door and
`packagedArtifactOwner`; `history` records the re-drive and its verdict.
- `automation.trigger-status-contract` (revision 6 → 7):
`fixtures.provisioning.why`, `steps[5]` and `acceptance[4].verify` name
step 5 in place of "record it blocked(fixture)"; `source` cites
`run-resume.ts#loadSuspendedRunStrict`; `history` records the re-drive
and its verdict. No clause sentence changed in either item.
## Why
Both clauses scored `blocked(fixture)` in both 18.2.0 waves. Read on
main d31329f:
- N1: a flow counts as packaged only when the package loader registered
it (`packagedArtifactOwner` reads the loader's set, never the body's
stamps), so a `?package=`-authored flow, a `POST /api/v1/automation`
flow and anything under a `POST /api/v1/packages` (authored) package are
deployment-authored. The install-local door's inline-manifest branch
registers through the kernel's `manifest` service as marketplace code
and announces `metadata:reloaded`, from which the automation engine
re-syncs its flows. It is mounted on a stock showcase boot unless
`OS_CLOUD_URL=off`, and the inline branch fetches nothing from the
cloud.
- A4: the resume door answers 503 only when the durable suspended-run
store throws on the strict load (`loadSuspendedRunStrict` inside
`resumeInternal`). No request makes it throw, but the store reads
`sys_automation_run` through the data engine, which rethrows a missing
table, so taking the table away for one resume is a live arm. The table
lives in the telemetry file beside the primary database
(`resolveTelemetryDbPath`), not in the primary.
No door is missing, so no product card is filed.
## Tests
No code changed, so no test was added. Both clauses were re-driven once,
REST only, on a fresh showcase boot built from d31329f (`OS_PORT=38917
pnpm dev -- --fresh -p 38917`, a stock boot with no env posture).
<details><summary>N1 on qa-second-packaged-caller</summary>
```text
POST /api/v1/marketplace/install-local -> 200 hotLoaded true, manifestId com.objectstack.qa.qasub
GET /api/v1/automation/qasub_second_notify_caller -> 200 status active, _provenance package, _packageId com.objectstack.qa.qasub
POST /api/v1/automation/showcase_notify_owner/toggle {"enabled": false} -> 409
{"code":"DELETE_RESTRICTED","message":"Flow 'showcase_notify_owner' cannot be disabled while 2 packaged flows still call it as a subflow: 'showcase_task_done_notify_owner', 'qasub_second_notify_caller'. Disabling it would break those callers mid-run at their subflow node with a late, inexplicable failure (ADR-0126 §7.3). Disable the calling flows 'showcase_task_done_notify_owner', 'qasub_second_notify_caller' first — or leave this one armed.","httpStatus":409}
GET /api/v1/data/sys_metadata_activation -> 200 records []
DELETE /api/v1/marketplace/install-local/com.objectstack.qa.qasub -> 200 cleanups [security.package-permissions ok]
POST /api/v1/automation/showcase_notify_owner/toggle {"enabled": false} -> 409 names showcase_task_done_notify_owner alone
```
Verdict for negative[1]: pass.
`examples/app-showcase/.objectstack/installed-packages/` was empty after
the teardown.
</details>
<details><summary>A4 (503 arm) on qa-flow-status-doors step 5</summary>
```text
POST /api/v1/automation/showcase_reassign_wizard/trigger {"params":{"recordId":TASK,"objectName":"showcase_task"}} -> 200 paused, runId run_59bec4ba-…
node:sqlite on PRIMARY.telemetry.db: sys_automation_run row count for the run = 1
ALTER TABLE sys_automation_run RENAME TO sys_automation_run__qa_off
POST /api/v1/automation/showcase_reassign_wizard/runs/RUNID/resume {"inputs":{"new_assignee":ADMIN}} -> 503
{"code":"STORE_UNAVAILABLE","message":"Durable suspended-run store unreachable for run 'run_59bec4ba-…' — retry once the store is available: The database refused to run this query for object 'sys_automation_run'. …","httpStatus":503}
ALTER TABLE sys_automation_run__qa_off RENAME TO sys_automation_run (row count still 1)
GET /api/v1/automation/showcase_reassign_wizard/runs/RUNID -> 200 status paused
POST /api/v1/automation/showcase_reassign_wizard/runs/RUNID/resume (same body) -> 200 apply node acted 1
```
Verdict for the 503 arm of acceptance[4]: pass, the suspension intact. A
first attempt aimed the rename at the primary file and answered `no such
table` there, which is why step 5 names the telemetry file.
</details>
## Acceptance notes
- Done-when line 1 asks for a keyed recipe each item references. An item
carries one `fixtures.provisioning.use` (the validator reads a single
string), and `automation.trigger-status-contract` already uses
`qa-flow-status-doors`, so the 503 arm is that recipe's step 5 rather
than a third key. A separate key would have no consumer and fail the
gate's unreferenced-recipe check.
- The card names "the boot or config that makes the run store
unavailable". There is none: the arm is an out-of-process edit of the
run's own telemetry file on a stock boot. It needs a file database and
Node 22.5+; the recipe's `requires` says so, and a run without them
records the arm `blocked(fixture)` with the in-process pin beside it.
- The install-local ledger lands in the project tree
(`examples/app-showcase/.objectstack/installed-packages/`, gitignored),
not in the `--fresh` tempdir, so the teardown DELETE is mandatory; the
recipe's `requires` and `teardown` say so.
- The packaged self-caller arm of `knownGaps[0]` needs the same kind of
install; it was not measured and stays as it was (the recipe's
`knownGaps[1]`).
- The branch merged origin/main f7c95cd after the re-drive; of the
paths this PR reads, the incoming commits touch only
`areas/api-backend.json`, `areas/approvals.json` and
`ObjectQL.validateData` in `packages/objectql/src/engine.ts` — not
`automation.json`, the engine's `find`, or any door cited.
## Verification
Gates at head 185f67d: `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` derived 16 commands; all 16 exit 0,
and `--ran` reconciles 16 derived, 16 run, 0 NOT-MEASURED. `node
scripts/check-platform-checklist.mjs`: OK, 7 area recipes, 12 item
references resolved, 7/7 recipes referenced, symbol anchors 1006/1016
resolved (10 on the named residual). No changeset: the diff touches only
`docs/qa/**`, which no package publishes (`skip-changeset`).
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(not touched)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (CI runs it)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset. (publishes
nothing)
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (not touched)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JQwxbYrT5jXrc7zvLFLnyA)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 63e3873 commit 59441b6
1 file changed
Lines changed: 130 additions & 13 deletions
0 commit comments