Skip to content

Requiring park causes prevents recording the normal owner-approval wait #9180

Description

@usirin

Two deliberate rules in this repo contradict each other, and the contradiction makes the ordinary
owner-approval wait unrecordable.

.fabrika.jsonc sets "parkCause": {"uncaused": "refuse"}. causeForEvent in
packages/fabrika-cli/src/lane/report.ts reads that as:
every BLOCKED with no --cause is Required, refused at exit 52 with the log unappended.
AWAITING-CP-APPROVAL maps to BLOCKED in that same file. So the terminal ship hands back when
owner approval is genuinely absent cannot be recorded at all.

Verified at origin/main. The closed PARK_CAUSES set is worktree-holds-branch,
head-behind-base, assembly-conflict, replay-conflict, campaign-paused, spawn-dead,
no-preview-render, no-design-manifest, no-rendered-delta, base-conflicted, queue-ejected,
head-ci-red, repair-budget-spent, replay-budget-spent. None names an owner-approval wait.

The conflict is by design on both sides, which is why no new token fixes it by itself. The
human:cp-approval row in
packages/fabrika-cli/src/recipe/parks.ts keys on
cause: null on purpose, and its own comment says why: BLOCKED out of ship folds to
human:cp-approval whatever the block was, so a row that ignored the cause would clear a park
recorded for something else by reading an approval nobody was waiting on. Adding an
awaiting-cp-approval token therefore also means re-keying that row, and the row can only be
re-keyed if the shipper always passes the token.

STRUCTURAL_PARK_CAUSES is not the escape here. Main added it for exactly this class, a cause
nobody can type read off the leaf, but its own admission rule is "only a leaf a single transition
can produce". human:cp-approval is the catch-all fold out of ship, produced by many transitions,
so binding it there would stamp every ship-stage block as an approval wait.

Triage note: the direction is open, and the two answers point opposite ways. Either (a) the
shipper starts naming the wait with a new awaiting-cp-approval cause and the parks.ts row is
re-keyed off null, or (b) requireCause stops applying to a leaf some recipe row already covers
with cause: null, so the existing route survives untouched. (a) changes what every recorder must
type; (b) narrows a guard this repo deliberately flipped on. That is why this leaves triage for a
person rather than a builder.

Triage note: searched, left standalone. Queried the park-cause surface and today's queue.
#9011 (no token for an unreadable CI verdict), #9106 (a spent machinery lap parks uncaused) and
#8889 (no token for a refused spawn) are the same family, but each is a missing token: the park
lands and the unpark refuses. This one sits upstream of that, because the park never lands at all.
#9186 is the nearest twin, an uncaused STOPPED the build skill says is legal, and is genuinely
separate: its leaf has no recipe row at all, so (b) above would not cover it and its own fix would
not cover this. No open epic owns the vocabulary, so this is minted standalone.

Triage note: not the branch-drift story. The same ship cp-approval read reported clean base
drift, and root chose ordinary queue integration for that clean head. This issue is only about the
remaining owner-approval wait.

Acceptance criteria

  • A ruling is recorded choosing between (a) a new awaiting-cp-approval cause token the shipper passes, with the parks.ts row re-keyed off cause: null, and (b) exempting from requireCause any park leaf a recipe row already covers with cause: null.
  • With parkCause.uncaused set to refuse, lane report <n> --task issue --token AWAITING-CP-APPROVAL records the terminal instead of refusing at exit 52.
  • After that record, recipe unpark still routes the lane to its existing human:cp-approval clearance rather than refusing or matching a different row.
  • A park recorded out of ship for a reason other than an approval wait still does not match the human:cp-approval clearance.
Original report

Summary

With requireCause enabled, lane report refuses AWAITING-CP-APPROVAL even when ship cp-approval has proven that owner approval is absent. The closed cause set has no owner-approval value.

What I was doing

Driving issue 8882 and PR #8915 through the reviewed, green head 52a8bad, then recording the actual wait for fresh owner approval.

What I observed

ship cp-approval returned stop awaiting-approval after reading four owners and two reviews. The following supported lane report returned exit 52 with the log unappended: lane report 8882 --task issue --token AWAITING-CP-APPROVAL --pr #8915. Its diagnostic required a cause from the closed list, which contains no owner-approval cause. The lane remains at ship, so the actual external wait cannot be recorded honestly through this route.

The same approval read also reported clean base drift. Root explicitly chose ordinary queue integration for that clean head under user authorization, preserving actual approval, review and CI gates. This observation concerns the remaining owner-approval wait, not inventing a branch defect as its substitute cause.

The inspected code maps AWAITING-CP-APPROVAL to BLOCKED. causeForEvent requires a supplied cause for every BLOCKED when requireCause is on. Yet routeForCause documents human:cp-approval as a known park keyed by its leaf without a cause. No config, code or lane history was changed to bypass the refusal.

Why it matters

A normal founder-owned wait cannot enter the ledger under a supported policy. The operator must leave the lane looking active or select a different cause that does not describe what it is waiting for.

Pointers

  • packages/fabrika-cli/src/lane/report.ts: AWAITING-CP-APPROVAL, PARK_CAUSES, causeForEvent, routeForCause.
  • packages/fabrika-cli/src/recipe/parks.ts: the existing owner-approval clearance.
  • claude-plugins/fabrika/skills/ship/SKILL.md: the ordinary AWAITING-CP-APPROVAL terminal has no cause when it is waiting on approval.
  • A decision lane parked for want of a ruling comment has no park cause to name #8983 is related vocabulary work for a missing decision ruling, not this existing owner-approval route.

Suggested next step (non-binding)

Reproduce with requireCause enabled and preserve the real owner-approval clearing read. Determine the smallest consistent way to record the existing known wait without weakening required causes for unknown parks.


Filed by an agent · session 01a089df-d8ca-74c0-be4c-ae8630f14c95 · 2026-09-11T02:27:51Z


Original report (verbatim)

Summary

With requireCause enabled, lane report refuses AWAITING-CP-APPROVAL even when ship cp-approval has proven that owner approval is absent. The closed cause set has no owner-approval value.

What I was doing

Driving issue 8882 and PR #8915 through the reviewed, green head 52a8bad, then recording the actual wait for fresh owner approval.

What I observed

ship cp-approval returned stop awaiting-approval after reading four owners and two reviews. The following supported lane report returned exit 52 with the log unappended: lane report 8882 --task issue --token AWAITING-CP-APPROVAL --pr #8915. Its diagnostic required a cause from the closed list, which contains no owner-approval cause. The lane remains at ship, so the actual external wait cannot be recorded honestly through this route.

The same approval read also reported clean base drift. Root explicitly chose ordinary queue integration for that clean head under user authorization, preserving actual approval, review and CI gates. This observation concerns the remaining owner-approval wait, not inventing a branch defect as its substitute cause.

The inspected code maps AWAITING-CP-APPROVAL to BLOCKED. causeForEvent requires a supplied cause for every BLOCKED when requireCause is on. Yet routeForCause documents human:cp-approval as a known park keyed by its leaf without a cause. No config, code or lane history was changed to bypass the refusal.

Why it matters

A normal founder-owned wait cannot enter the ledger under a supported policy. The operator must leave the lane looking active or select a different cause that does not describe what it is waiting for.

Pointers

  • packages/fabrika-cli/src/lane/report.ts: AWAITING-CP-APPROVAL, PARK_CAUSES, causeForEvent, routeForCause.
  • packages/fabrika-cli/src/recipe/parks.ts: the existing owner-approval clearance.
  • claude-plugins/fabrika/skills/ship/SKILL.md: the ordinary AWAITING-CP-APPROVAL terminal has no cause when it is waiting on approval.
  • A decision lane parked for want of a ruling comment has no park cause to name #8983 is related vocabulary work for a missing decision ruling, not this existing owner-approval route.

Suggested next step (non-binding)

Reproduce with requireCause enabled and preserve the real owner-approval clearing read. Determine the smallest consistent way to record the existing known wait without weakening required causes for unknown parks.


Filed by an agent · session 01a089df-d8ca-74c0-be4c-ae8630f14c95 · 2026-09-11T02:27:51Z

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    axis:pipeline-hardeningStanding cross-cutting axis: pipeline hardening (was milestone #1; go-forward label)p2Lowest priorityready-for:agentAn execution engine may pick this up.status:triagedTriage signed off; ready for write-code to picktype:bugBehavior diverges from intent

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions