Skip to content

Commit e0abc38

Browse files
baozhoutaoclaude
andauthored
qa+fix: ADR-0126 scoped checklist sweep (#12438) + Setup nav entry for the packaged-automation page (#12457) (#12491)
* qa(checklist): scoped coverage sweep for ADR-0126 packaged flow/action disable+clone (#12438) Scoped sweep triggered by acceptance card #12438 (Epic #12150). The shipped ADR-0126 surface (sys_metadata_activation ledger, packaged flow toggle + subflow guard, flow clone, ACTION_DISABLED dispatch consult, operator gate, Setup packaged-automation board) had zero checklist coverage. - 14 new items across 5 areas (automation x4, api-backend x2, access-security x3, platform-core x3, studio-authoring x2), ledger 207 -> 221; every clause grounded in source, expected-fail probes for the defects found while grounding (FOLLOW-UPS SS8a D16-D22) - automation.flow-toggle-kill-switch rev 2: re-sourced off the retired flowEnabled map onto the ledger projection (ADR-0126 SS7.2) - coverage.json: new items mapped into flow/action/permission/object/ view/dashboard kinds; still 0 waivers - FOLLOW-UPS.md SS8: product defects (Setup nav entry missing - card A1 will fail; /automation write-door lock bypass; clone engine-only; dead subflow remedy; extension-field override), docs drift, card accuracy notes, fixture asks - enumSource pin added: TenancyPostureSchema (3 postures) Validator green: 221 items, 31 kinds mapped, 0 waived, traps 19/19. Refs #12438, Epic #12150, ADR-0126 Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SKUXt6sKgAeCEtjiuwNuhq * fix(platform-objects): Setup nav entry for the packaged-automation page (#12457) ADR-0126 SS7.4's Setup page shipped complete in the console (objectui app-shell, component ref automation:packaged) but no framework NavigationContribution ever named the ref - the page was reachable only by a hand-typed URL and Setup's sidebar carried no entry (epic #12150 L5/L6-UI closed with the framework half missing). - SETUP_NAV_CONTRIBUTIONS: nav_packaged_automation (type component, componentRef automation:packaged) in group_apps beside Packages (ADR-0084: package administration is Operate). Deliberately no requiresService (action switches work without the automation service, #12419) and no requiredPermissions (matches nav_packages; write doors enforce manage_metadata / the SS5 operator gate server-side) - labels in all four locales + recorded source hashes - setup-packaged-automation-nav.test.ts pins the framework half of the cross-repo contract (objectui's navContribution test pins its half) - FOLLOW-UPS SS8a D16 row updated with the filed issue ref - changeset: @objectstack/platform-objects patch Validated: platform-objects vitest suites green (204 tests incl. i18n parity/tombstone/source-hash), check:app-nav-i18n green (54 merged setup nav ids, 4 locales). Fixes #12457. Refs #12438, Epic #12150, ADR-0126 SS7.4 Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SKUXt6sKgAeCEtjiuwNuhq --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3bc2e38 commit e0abc38

17 files changed

Lines changed: 1625 additions & 9 deletions
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
"@objectstack/platform-objects": patch
3+
---
4+
5+
fix(platform-objects): add the Setup nav entry for the packaged-automation page (#12457, ADR-0126 §7.4)
6+
7+
The packaged-automation page (on/off per packaged flow/action, clone for
8+
flows) shipped complete in the console (objectui app-shell, registered under
9+
the component ref `automation:packaged`), but no framework
10+
`NavigationContribution` ever named that ref — so on every stock boot the
11+
page was reachable only by a hand-typed URL
12+
(`/apps/setup/component/automation/packaged`), and Setup's sidebar carried no
13+
entry. Epic #12150's L5/L6-UI cards closed with the objectui half pinned and
14+
the framework half missing; `content/docs/build-without-code.mdx` promises
15+
the page publicly.
16+
17+
`SETUP_NAV_CONTRIBUTIONS` now contributes `nav_packaged_automation`
18+
(`type: 'component'`, `componentRef: 'automation:packaged'`) in `group_apps`
19+
beside Packages — package administration is Operate (ADR-0084), and ADR-0126
20+
§7.4 rules "Studio keeps the editing; Setup gets the operational state". The
21+
entry deliberately carries no `requiresService: 'automation'` (the action
22+
switches ride the `sys_metadata_activation` ledger this package registers and
23+
work on compositions with no automation service, #12419) and no
24+
`requiredPermissions` (matches `nav_packages`: the app's `setup.access` gates
25+
entry, the activation write doors enforce `manage_metadata` / the §5 operator
26+
gate server-side). Labels land in all four locales with recorded source
27+
hashes; `setup-packaged-automation-nav.test.ts` pins the framework half of
28+
the cross-repo contract the objectui nav test pins from its side.

docs/qa/platform-checklist/FOLLOW-UPS.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,101 @@ recorded as accepted scope. Until then, only a sweep like this one can catch it.
278278
- 2FA challenge gate + lockout: covered (`identity-auth.auth-method-matrix` +
279279
`two-factor-lockout.dogfood.test.ts`); endpoint existence pinned by
280280
`auth-route-ledger.conformance.test.ts`.
281+
282+
## 8. Scoped sweep 2026-08-26 — ADR-0126 验收卡 #12438 (packaged flow/action disable + clone)
283+
284+
Scoped sweep triggered by acceptance card #12438 (Epic #12150, nine PRs merged at
285+
af56546). Three read-only hunters (routes/runtime · Setup/Studio UI · docs claims)
286+
diffed the shipped ADR-0126 surface against the ledger; **the whole surface was
287+
uncovered** (zero hits for `ADR-0126|sys_metadata_activation|ACTION_DISABLED` across
288+
the checklist before this sweep). 14 items were authored + 1 revision in the same
289+
change (automation ×4; api-backend ×2; access-security ×3; platform-core ×3;
290+
studio-authoring ×2; `automation.flow-toggle-kill-switch` re-sourced rev 2 — its old
291+
source cited the `flowEnabled` map §7.2 retired). Ledger 207 → 221 items. What follows
292+
is what is NOT a checklist item.
293+
294+
### 8a. Product defects found while grounding (decide handling)
295+
296+
Each is captured inside a checklist item as an expected-fail probe or knownGap, so a
297+
run records actual behavior instead of ticking green.
298+
299+
| # | defect | evidence | captured in | sensitivity |
300+
|---|---|---|---|---|
301+
| D16 | **Setup packaged-automation page is unreachable — no nav entry.** The page + registry ref `automation:packaged` shipped in objectui (`app-shell/src/views/setup/PackagedAutomationPage.tsx`, `services/builtinComponents.tsx:64-69`), but `packages/platform-objects/src/apps/setup-nav.contributions.ts` names no such item (only `developer:packages` at :51); reachable only by typed URL `/apps/setup/component/automation/packaged`. Epic L5 (#6301) and L6-UI (#6412) are CLOSED, so this is a dropped half, not pending work. Card **A1 is expected to fail**; `build-without-code.mdx:37` ships the promise publicly (docs ahead of surface — the sequencing ADR §8.5 asked to avoid). | objectstack `setup-nav.contributions.ts:32-171` vs objectui `PackagedAutomationPage.navContribution.test.tsx` (pins only the objectui half) | automation.setup-packaged-automation-board (expected-fail nav clause — a typed-URL pass must not tick it) | UX/release — **FILED as #12457** (2026-08-26); testers warned on #12438 |
302+
| D17 | **`PUT`/`DELETE /api/v1/automation/:name` bypass the packaged lock**`manage_metadata` alone re-registers/unregisters a packaged flow's live definition; `registerFlow` has zero `_lock`/provenance check, while `/meta/flow` refuses the same write. ADR-0126 §2 "refused loudly at the write door" is unimplemented at this door. | `packages/runtime/src/domains/automation.ts:1826-1865`; `packages/services/service-automation/src/engine.ts:2625-2730` | access-security.packaged-flow-write-door-parity (expected-fail parity clauses) | integrity — admin-gated, not an escalation; safe to file |
303+
| D18 | **The flow clone is engine-registry-only** — no `sys_metadata` write on the clone path, `_packageId`/`_provenance` stripped, no post-clone navigation; Studio's Automations rail lists package-scoped metadata, so a package-less engine-only clone matches no package. "The clone is an ordinary flow, yours to edit in Studio" (ADR §1.3/§7.1, `build-without-code.mdx:37`) is unproven; restart survival unknown. | `domains/automation.ts:1414-1436` (registerFlow only); `flow-clone.ts:225`; objectui `StudioDesignSurface.tsx:3286`; `PackagedAutomationPage.tsx:302-313` | automation.packaged-flow-clone-contract (honest restart+Studio clause, expected-fail) | correctness — safe to file |
304+
| D19 | **The subflow refusal's own remedy is dead** — "Disable the calling flow(s) first" is what the 409 prescribes, but `packagedSubflowCallers` scans the registered flow map with **no activation check**, so an already-DISABLED caller still guards its callee; the prescribed sequence can never complete. No test covers the sequence. | `engine.ts:2932-2947` (no activation consult) vs `:2992-2996` (the prescription); ADR §7.3 | automation.packaged-flow-subflow-disable-refusal (expected-fail remedy-sequence clause) | correctness — safe to file |
305+
| D20 | **Extension-field collision silently OVERRIDES the shipped base field**`mergeObjectDefinitions` spreads `extension.fields` over `base.fields`, and the authoring schema documents "Fields to add/override" with priority "wins on conflict". No generic collision gate exists (`managed-extension-fields` covers better-auth sys objects only; ADR §3 adopts it as *prior art*, not a live gate). May be by-design — but then integrations.mdx's "never by reshaping what shipped" overstates. | `packages/objectql/src/registry.ts:146`; `packages/spec/src/data/object.zod.ts:2979,2996-2997` | platform-core.packaged-object-extend-only (knownGap, do-not-file-as-FAIL rule) | integrity/design — needs a ruling |
306+
| D21 | **Non-durable toggle disclosure is a server log line only** — with no activation ledger attached, `toggleFlow` warns "IN PROCESS ONLY … will NOT survive a restart", but the response body (`{name, enabled}`) and every UI surface carry nothing; card 已知边界 3's asymmetry has no user-facing channel and no docs sentence anywhere. | `engine.ts:3018-3028`; `domains/automation.ts:1321-1322` | — (not an item; needs a maintainer call on the channel: response field vs UI copy vs docs) | UX-integrity — maintainer call |
307+
| D22 | **`POST /automation/:name/clone` is unledgered** — live route absent from `route-ledger.ts` and from the JS client; `api-backend.route-ledger-live-parity` runs ledger→live only, so an unledgered mount is invisible to it. Suggest a ledger row now; consider a reverse-parity (live→ledger) item as a standing gate. | `domains/automation.ts:1340` vs `route-ledger.ts:316-336` | — (not an item) | low — internal discipline |
308+
309+
Two objectui-side polish rows captured inside `automation.setup-packaged-automation-board`
310+
rather than as defect rows: `actionErrorDetail` drops `details[]`, so field-level
311+
prescriptions on validation refusals never reach the operator (`packages/core/src/actions/actionErrorDetail.ts:27-35`
312+
— a narrowing, not a rewrite); and the page renders live switches for a plain member
313+
with the refusal discovered only after the click (`ComponentNavView` has no gate; ledger
314+
reads are deliberately open per `sys-metadata-activation.object.ts:153-157` — record the
315+
posture, then decide which shape is wanted).
316+
317+
### 8b. Docs drift (PD#10 class — file as docs fixes, not checklist items)
318+
319+
- **`content/docs/kernel/contracts/metadata-service.mdx:211-324`** teaches the superseded
320+
three-layer overlay protocol as the customization architecture — which ADR-0126 §6.4
321+
forbids citing — and its worked example overlays an **`object`** (tier B,
322+
`allowOrgOverride:false`): the exact `NOT_OVERRIDABLE` phantom write the §6.1 wall refuses.
323+
- **`content/docs/protocol/objectui/concept.mdx:415-450`** (+ `index.mdx:446`) promises
324+
per-tenant field-level object customization ("Make phone required", "Add custom field
325+
vip_status") — contradicts Regime E and the sentence now shipped at
326+
`capabilities/integrations.mdx:17` ("not by editing what shipped").
327+
- **`build-without-code.mdx`** routes no-code admins to a code-only mechanism without
328+
saying so — extension packages ship in code with the package
329+
(`data-modeling/object-extensions.mdx:22,28`); one clause ("via an extension package
330+
your developer ships") closes it.
331+
- **The shipped Regime-C doors are undocumented**: no docs page for
332+
`/automation/:name/clone`, `/actions/_activation/:object/:action`, the subflow 409, or
333+
the §5 operator gate; `ACTION_DISABLED` appears only in the generated ledgers;
334+
`references/api/automation-api.mdx:22`'s toggle row predates the durable/gated semantics.
335+
- **ADR-0126's header still reads `Status: Proposed`** while all nine epic PRs are merged
336+
at af56546 — flip it (the acceptance act evidently happened).
337+
338+
### 8c. Card-accuracy notes for the tester (#12438)
339+
340+
- **A1 will fail** (D16); the typed URL works and the rest of A/B/C is testable through it.
341+
- **已知边界 3 is inaccurate as worded**: with the ledger attached, `toggleFlow` writes a
342+
row for ANY flow it holds (`packageId: ''` for non-packaged — `actions.ts:139-145`
343+
states the design); the non-persistent case is the ledger-less boot (D21), not
344+
"non-packaged flows" per se.
345+
- **D1's refusal on a stock (single-posture) boot is the `manage_metadata` tier** — the §5
346+
posture gate is deliberately inert under `single`; and the two doors speak different
347+
sentences (flow: `FLOW_ENABLEMENT_DENY_MESSAGE`; action: the shared activation-gate
348+
wording). **D2 needs a `group`/`isolated` boot** (enterprise `@objectstack/organizations`)
349+
— no stock fixture; unit-pinned only.
350+
- **B1: clone requires a new machine name AND a new label**, both mandatory server-side.
351+
- **C1's code is `ACTION_DISABLED`; the packaged-flow disable reuses `FLOW_DISABLED`**
352+
distinguish the ledger disable from a Studio `status` disable by the message's
353+
`sys_metadata_activation` phrase, never by code alone.
354+
355+
### 8d. Fixtures worth adding (would un-block clauses recorded as knownGaps)
356+
357+
- two stock objects sharing an action machine name → unblocks the 409 `RESOURCE_CONFLICT`
358+
ambiguity arm (`api-backend.action-activation-door-contract`).
359+
- a `group`/`isolated` posture boot recipe → unblocks the §5 operator-gate legs
360+
(`access-security.activation-write-operator-gate`) and card row D2.
361+
- a documented no-automation lean-composition boot for manual runners → the dogfood
362+
harness (`bootStack(showcaseStack)` minus automation) is currently the only path for
363+
`platform-core.activation-ledger-registration-home`'s 503-turnaround leg.
364+
365+
### 8e. Checked and CLEAN (so the next sweep does not re-derive)
366+
367+
- **E1's three-tier language landed verbatim** at `capabilities/integrations.mdx:17` and
368+
`build-without-code.mdx:37`; repo-wide, no unconditional "install then customize in
369+
Studio" claim remains in `content/docs`.
370+
- **The dashboard overlay door exists** (`dashboard allowOrgOverride: true`,
371+
`packages/spec/src/kernel/metadata-plugin.zod.ts:787`) — the display-class item asserts
372+
the tier-1 promise on both view and dashboard.
373+
- **`TenancyPostureSchema` is enumSource-pinnable** (direct inline `z.enum`, 3 members) —
374+
pinned on the operator-gate item. **`sys_metadata_activation.metadata_type` is NOT
375+
pinnable** (untyped `Field.text`, string-literal writers `'flow'`/`'action'`) —
376+
hand-enumerated on the row-contract item and flagged un-pinned.
377+
- **No security-sensitive finding to withhold**: D16–D22 are admin-gated behaviors or
378+
disclosure-shape issues; nothing here discloses an unfixed privilege escalation.

0 commit comments

Comments
 (0)