Skip to content

feat(cli): lint ADR-0044 approval revise-loop footguns at compile time#2279

Merged
os-zhuang merged 1 commit into
mainfrom
feat/lint-approval-revise-loop
Jun 24, 2026
Merged

feat(cli): lint ADR-0044 approval revise-loop footguns at compile time#2279
os-zhuang merged 1 commit into
mainfrom
feat/lint-approval-revise-loop

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What & why

First slice of #2274 (AI Build-mode awareness of the ADR-0044 revise loop). objectstack compile's flow anti-pattern linter (lint-flow-patterns.ts) — whose stated job is to "guide the author, very often an AI generating templates, toward the robust pattern" — now catches the two send-back-for-revision shapes an approval flow most commonly gets wrong:

  • Dead-end revise — an approval node has a revise out-edge but no path loops back to it. This is a valid DAG, so registerFlow accepts it — yet the submitter reworks the record with nowhere to resubmit. The linter is the only place that catches this footgun.
  • Un-declared revise loop — the loop returns to the approval but the closing edge isn't type: 'back', so registerFlow rejects it as an un-declared cycle. The lint fires at compile time with the specific fix ("mark the resubmit edge type: 'back'"), so the author/agent corrects it before registration.
  • maxRevisions: 0 + a revise edge — self-contradictory (send-back disabled → the branch always auto-rejects); flagged too.

Advisory warnings only — never fails the build (consistent with the existing #1874 rules). This mirrors, server-side, the client-side cycle surfacing shipped in objectui (#1958).

Scope

This is the deterministic guardrail piece of #2274 (compile-time structured feedback). The remaining #2274 work — agent prompt/few-shot, flow-builder.zod.ts back edge style, and an eval, plus the optional auto-repair — stays tracked on #2274.

Files

  • packages/cli/src/utils/lint-flow-patterns.tsscanApprovalReviseLoops() + 3 rule ids (flow-approval-revise-dead-end, -unmarked-backedge, -disabled).
  • packages/cli/src/utils/lint-flow-patterns.test.ts — 5 new cases.

Verification

  • @objectstack/cli tests: 28 passing (5 new — declared loop accepted; unmarked loop flagged; dead-end flagged; maxRevisions:0 flagged; normal approval not flagged).
  • tsc -p tsconfig.build.json clean for the changed files; eslint clean.

Refs #2274, #1770 (ADR-0044). Pairs with objectui #1954 / #1955 / #1958.

🤖 Generated with Claude Code

`objectstack compile` (lint-flow-patterns) now warns on two send-back-for-
revision shapes an AI authoring an approval flow gets wrong:

- Dead-end revise: an approval with a `revise` out-edge but no path looping
  back to it — a valid DAG that `registerFlow` ACCEPTS, yet the submitter
  reworks the record with nowhere to resubmit. The linter is the only place
  that catches this.
- Un-declared revise loop: the loop returns to the approval but the closing
  edge isn't `type: 'back'`, so `registerFlow` rejects it as an un-declared
  cycle — the lint fires at compile time with the specific fix.

Also flags `maxRevisions: 0` alongside a `revise` edge (send-back disabled).
Advisory only; never fails the build. Mirrors the client-side rule shipped in
objectui (#1958).

Refs #2274, #1770 (ADR-0044).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@os-zhuang
os-zhuang merged commit 84784fc into main Jun 24, 2026
1 of 2 checks passed
@os-zhuang
os-zhuang deleted the feat/lint-approval-revise-loop branch June 24, 2026 09:46
@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Building Building Preview, Comment Jun 24, 2026 9:46am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jun 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli.

15 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/cloud-artifact-api.mdx (via packages/cli)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/cli)
  • content/docs/concepts/packages.mdx (via @objectstack/cli)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/cli)
  • content/docs/guides/authentication.mdx (via @objectstack/cli)
  • content/docs/guides/client-sdk.mdx (via @objectstack/cli)
  • content/docs/guides/hook-bodies.mdx (via packages/cli)
  • content/docs/guides/packages.mdx (via @objectstack/cli)
  • content/docs/guides/project-scoping.mdx (via @objectstack/cli)
  • content/docs/guides/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/guides/runtime-services/index.mdx (via packages/cli)
  • content/docs/guides/skills.mdx (via packages/cli)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/cli)
  • content/docs/protocol/objectos/realtime-protocol.mdx (via @objectstack/cli)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

os-zhuang added a commit that referenced this pull request Jun 24, 2026
… on main) (#2283)

`packages/cli/src/utils/lint-flow-patterns.test.ts:190` had an untyped `edges`
parameter (TS7006 under the build's noImplicitAny), introduced by #2279. The
TypeScript Type Check job builds the whole workspace, so this fails CI for
*every* open PR. Add the edge-array type (and an explicit approvalConfig type).
Test-only; no behavior change.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jun 24, 2026
…vision shape (#2294)

The objectstack-automation skill documented approve/reject approvals (ADR-0019)
but not the ADR-0044 revise loop, so AI-authored approval flows omit it (and a
revise loop hand-built without the back-edge gets rejected by registerFlow).

Add a "Send-back for revision" section to the Approvals area: the `revise`
out-edge → a signal `wait` node, the resubmit edge typed `type: 'back'` (the only
thing that legalizes the cycle — graph-minus-back-edges must be a DAG, authors
opt in edge by edge), and the `maxRevisions` budget. Calls out the two shapes the
compile-time flow lint flags (dead-end revise; unmarked back-edge) and points at
the canonical showcase_budget_approval.

Completes the agent-teaching slice of #2274 (ADR-0044), alongside the compile-time
lint (#2279), the flow-builder `back` edge style (#2291), and the engine's
already-specific cycle-rejection hint.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jun 24, 2026
)

Adds skills/objectstack-automation/evals/approvals/test-revise-loop.md, the first
concrete eval under the skills' (previously placeholder) evals/ format — Scenario
/ Expected Output / Common Mistakes / Validation Criteria. It pins the expected
send-back-for-revision shape (revise branch + signal wait + type:'back' resubmit +
maxRevisions), the three footguns the compile-time lint flags, and registerFlow-
based pass criteria.

This is the authorable (a) half of #2274's eval slice. The executable eval RUNNER
(b) remains a separate platform project — the skills' evals/ harness is still
"not yet implemented" per each dir's README.

Refs #2274, #1770 (ADR-0044). Builds on the lint (#2279) and skill (#2294).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 5, 2026
fix(plugin-form): dedupe master-detail create toast + localize Cancel (#2278) (#2279)

objectui@ec9c8eec8e1ce7310e78511f4beee09ba1d98862
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant