mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-07 03:00:29 +00:00
parent
c715e9e0e7
commit
3f6aeb0f34
7 changed files with 858 additions and 14 deletions
518
run.json
518
run.json
File diff suppressed because one or more lines are too long
1
stages/008-verify@1/output.log
Normal file
1
stages/008-verify@1/output.log
Normal file
|
|
@ -0,0 +1 @@
|
|||
blob://sha256/892028c98394b32e6bfcb04ebd4e24b953ae664fd34c494130103eea91b73118
|
||||
8
stages/008-verify@1/script_timing.json
Normal file
8
stages/008-verify@1/script_timing.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"output": "blob://sha256/892028c98394b32e6bfcb04ebd4e24b953ae664fd34c494130103eea91b73118",
|
||||
"exit_code": 1,
|
||||
"duration_ms": 2101,
|
||||
"termination": "exited",
|
||||
"output_bytes": 137,
|
||||
"live_streaming": true
|
||||
}
|
||||
6
stages/008-verify@1/status.json
Normal file
6
stages/008-verify@1/status.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"outcome": "failed",
|
||||
"notes": null,
|
||||
"failure_reason": "Script failed with exit code: 1\n\n## output\nFrom https://github.com/fabro-sh/fabro\n * branch main -> FETCH_HEAD\nmerge: origin/main - not something we can merge\n",
|
||||
"timestamp": "2026-06-01T20:07:26.149263Z"
|
||||
}
|
||||
318
stages/009-fixup@1/prompt.md
Normal file
318
stages/009-fixup@1/prompt.md
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
Goal: # Remove Automation Master Enabled Gate Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Remove the top-level automation `enabled` field so trigger-level `enabled` is the only activation control.
|
||||
|
||||
**Architecture:** Automations keep their existing file-backed TOML store and REST API, but the top-level master gate disappears from the Rust domain model, persisted TOML, OpenAPI schemas, generated clients, and web UI. API/manual run creation checks only for an enabled `api` trigger. No migration or legacy parser path is added because automations are brand new; TOML that still contains top-level `enabled` is obsolete input.
|
||||
|
||||
**Tech Stack:** Rust, serde/TOML, Axum, OpenAPI/progenitor, TypeScript Axios client generation, React 19, SWR, Tailwind CSS.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
- Modify `lib/crates/fabro-automation/src/model.rs` for the core type and TOML shape.
|
||||
- Modify `lib/crates/fabro-automation/src/store.rs` for unit fixtures that create automation drafts/replacements.
|
||||
- Modify `lib/crates/fabro-server/src/server/handler/automations.rs` for API-trigger conflict wording.
|
||||
- Modify `lib/crates/fabro-server/tests/it/api/automations.rs` for HTTP fixtures and behavior tests.
|
||||
- Modify `docs/public/api-reference/fabro-api.yaml` and regenerate `lib/packages/fabro-api-client/src/**`.
|
||||
- Modify `lib/crates/fabro-api/tests/automation_round_trip.rs` for Rust/OpenAPI type parity.
|
||||
- Modify `apps/fabro-web/app/components/automation-form.tsx`, `apps/fabro-web/app/routes/automations-new.tsx`, `apps/fabro-web/app/routes/automations-edit.tsx`, `apps/fabro-web/app/routes/automation-detail.tsx`, and `apps/fabro-web/app/routes/automations.tsx` for UI state and trigger-derived run availability.
|
||||
|
||||
## Task 1: Remove The Domain Master Gate
|
||||
|
||||
**Files:**
|
||||
- Modify: `lib/crates/fabro-automation/src/model.rs`
|
||||
- Modify: `lib/crates/fabro-automation/src/store.rs`
|
||||
|
||||
- [ ] Remove `pub enabled: bool` from `Automation`, `AutomationDraft`, `AutomationReplace`, and `PersistedAutomation`.
|
||||
- [ ] Remove `enabled` from every conversion between `AutomationDraft`, `AutomationReplace`, `PersistedAutomation`, and `Automation`.
|
||||
- [ ] Update `Automation::enabled_api_trigger()` to return an enabled API trigger without checking a top-level automation flag:
|
||||
|
||||
```rust
|
||||
/// Returns the enabled API trigger if the automation has one.
|
||||
/// Returns `None` when the automation has no enabled API trigger.
|
||||
#[must_use]
|
||||
pub fn enabled_api_trigger(&self) -> Option<&ApiTrigger> {
|
||||
self.triggers.iter().find_map(|trigger| match trigger {
|
||||
AutomationTrigger::Api(trigger) if trigger.enabled => Some(trigger),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] Remove the now-unused `default_true()` helper if no other code in the file still uses it.
|
||||
- [ ] Update `persisted_toml_applies_defaults_and_canonicalizes_without_id_or_revision` so the fixture has no top-level `enabled = true`, does not assert `automation.enabled`, and asserts the canonical TOML has no top-level `enabled` line:
|
||||
|
||||
```rust
|
||||
assert!(!top_level_lines(&toml).any(|line| line.starts_with("enabled = ")));
|
||||
```
|
||||
|
||||
- [ ] Add a focused no-compatibility test in `lib/crates/fabro-automation/src/model.rs`:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn persisted_toml_rejects_legacy_top_level_enabled() {
|
||||
let bytes = br#"
|
||||
name = "Legacy"
|
||||
enabled = false
|
||||
|
||||
[target]
|
||||
repository = "fabro-sh/fabro"
|
||||
ref = "main"
|
||||
workflow = "release"
|
||||
|
||||
[[triggers]]
|
||||
type = "api"
|
||||
id = "manual"
|
||||
enabled = true
|
||||
"#;
|
||||
|
||||
let result = Automation::from_toml_bytes(AutomationId::new("legacy").unwrap(), bytes);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] Update `lib/crates/fabro-automation/src/store.rs` test helpers so `draft()` and `replacement()` no longer set top-level `enabled`.
|
||||
- [ ] Run:
|
||||
|
||||
```bash
|
||||
cargo nextest run -p fabro-automation
|
||||
```
|
||||
|
||||
Expected: all `fabro-automation` tests pass.
|
||||
|
||||
## Task 2: Update Server Behavior And Tests
|
||||
|
||||
**Files:**
|
||||
- Modify: `lib/crates/fabro-server/src/server/handler/automations.rs`
|
||||
- Modify: `lib/crates/fabro-server/tests/it/api/automations.rs`
|
||||
|
||||
- [ ] Change the `create_automation_run` conflict detail from:
|
||||
|
||||
```rust
|
||||
"automation is disabled or has no enabled API trigger"
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```rust
|
||||
"automation has no enabled API trigger"
|
||||
```
|
||||
|
||||
Keep the existing code `"automation_api_trigger_disabled"` for compatibility with current clients and tests.
|
||||
|
||||
- [ ] Remove top-level `"enabled": true` from `automation_body()`.
|
||||
- [ ] Remove top-level `"enabled": false` from `replacement_body()`.
|
||||
- [ ] Delete `disabled_automation_run_endpoint_returns_conflict_code`; the master gate no longer exists.
|
||||
- [ ] Keep `disabled_api_trigger_run_endpoint_returns_conflict_code` and `missing_api_trigger_run_endpoint_returns_conflict_code` as the authoritative inactive-run tests.
|
||||
- [ ] Update any test that mutates `body["enabled"]` or expects top-level enabled in automation JSON/TOML.
|
||||
- [ ] Run:
|
||||
|
||||
```bash
|
||||
cargo nextest run -p fabro-server automations
|
||||
```
|
||||
|
||||
Expected: automation integration tests pass.
|
||||
|
||||
## Task 3: Update OpenAPI And Generated API Types
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/public/api-reference/fabro-api.yaml`
|
||||
- Modify: `lib/crates/fabro-api/tests/automation_round_trip.rs`
|
||||
- Regenerate: `lib/packages/fabro-api-client/src/**`
|
||||
|
||||
- [ ] In the `Automation` schema, remove top-level `enabled` from `required` and `properties`.
|
||||
- [ ] In `CreateAutomationRequest`, remove top-level `enabled` from `properties`.
|
||||
- [ ] In `ReplaceAutomationRequest`, remove top-level `enabled` from `required` and `properties`.
|
||||
- [ ] Keep `enabled` on `AutomationApiTrigger` and `AutomationScheduleTrigger`.
|
||||
- [ ] Update the `POST /api/v1/automations/{id}/runs` `409` description from:
|
||||
|
||||
```yaml
|
||||
description: Automation is disabled or has no enabled API trigger
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```yaml
|
||||
description: Automation has no enabled API trigger
|
||||
```
|
||||
|
||||
- [ ] Update `lib/crates/fabro-api/tests/automation_round_trip.rs` so the `Automation`, `CreateAutomationRequest`, and `ReplaceAutomationRequest` JSON fixtures no longer include top-level `"enabled"`.
|
||||
- [ ] Run:
|
||||
|
||||
```bash
|
||||
cargo build -p fabro-api
|
||||
```
|
||||
|
||||
Expected: progenitor type generation succeeds.
|
||||
|
||||
- [ ] Run:
|
||||
|
||||
```bash
|
||||
cargo nextest run -p fabro-api automation_round_trip
|
||||
```
|
||||
|
||||
Expected: automation type identity and JSON parity tests pass.
|
||||
|
||||
- [ ] Regenerate the TypeScript client:
|
||||
|
||||
```bash
|
||||
cd lib/packages/fabro-api-client && bun run generate
|
||||
```
|
||||
|
||||
Expected: generated model files remove top-level `enabled` from `Automation`, `CreateAutomationRequest`, and `ReplaceAutomationRequest`.
|
||||
|
||||
## Task 4: Remove The Web UI Master Toggle
|
||||
|
||||
**Files:**
|
||||
- Modify: `apps/fabro-web/app/components/automation-form.tsx`
|
||||
- Modify: `apps/fabro-web/app/routes/automations-new.tsx`
|
||||
- Modify: `apps/fabro-web/app/routes/automations-edit.tsx`
|
||||
- Modify: `apps/fabro-web/app/routes/automation-detail.tsx`
|
||||
- Modify: `apps/fabro-web/app/routes/automations.tsx`
|
||||
|
||||
- [ ] Remove `enabled` from `AutomationFormValues` and `EMPTY_AUTOMATION_FORM`.
|
||||
- [ ] Remove `enabled: automation.enabled` from `automationToFormValues`.
|
||||
- [ ] Delete the `Row title="Enabled"` block from `AutomationFormFields`.
|
||||
- [ ] Remove `enabled: values.enabled` from the create payload in `automations-new.tsx`.
|
||||
- [ ] Remove `enabled: values.enabled` from the replace payload in `automations-edit.tsx`.
|
||||
- [ ] In `isFormValid`, remove the requirement that at least one trigger is enabled. The final return should only require non-empty ID, name, repository, ref, and workflow:
|
||||
|
||||
```ts
|
||||
return (
|
||||
values.id.trim() !== "" &&
|
||||
values.name.trim() !== "" &&
|
||||
values.repository.trim() !== "" &&
|
||||
values.ref.trim() !== "" &&
|
||||
values.workflow.trim() !== ""
|
||||
);
|
||||
```
|
||||
|
||||
- [ ] In `automation-detail.tsx`, change run availability to:
|
||||
|
||||
```ts
|
||||
const canRun = apiTrigger?.enabled === true;
|
||||
```
|
||||
|
||||
- [ ] In `automation-detail.tsx`, remove `StatusChip`, remove its use, and simplify the Run button `title` so only a missing/disabled API trigger explains the disabled state:
|
||||
|
||||
```ts
|
||||
title={!apiTrigger?.enabled ? "Enable the API trigger to run it" : undefined}
|
||||
```
|
||||
|
||||
- [ ] In `automations.tsx`, extend `AutomationRow` with `apiEnabled: boolean`, set it from the enabled API trigger in `mapAutomations`, and pass `disabled={deleting || !automation.apiEnabled || (runningId !== null && runningId !== automation.id)}` to the run button path.
|
||||
- [ ] In `AutomationCard`, make the run button title reflect trigger-disabled state:
|
||||
|
||||
```tsx
|
||||
title={
|
||||
running
|
||||
? "Starting run..."
|
||||
: automation.apiEnabled
|
||||
? "Run automation"
|
||||
: "Enable the API trigger to run it"
|
||||
}
|
||||
```
|
||||
|
||||
Use exactly this title text for the disabled/run states; do not change visible button copy.
|
||||
|
||||
- [ ] Run:
|
||||
|
||||
```bash
|
||||
cd apps/fabro-web && bun run typecheck
|
||||
```
|
||||
|
||||
Expected: TypeScript passes with no `automation.enabled` references.
|
||||
|
||||
## Task 5: Final Verification
|
||||
|
||||
**Files:**
|
||||
- No additional source edits expected.
|
||||
|
||||
- [ ] Run the focused backend checks:
|
||||
|
||||
```bash
|
||||
cargo nextest run -p fabro-automation
|
||||
cargo nextest run -p fabro-api automation_round_trip
|
||||
cargo nextest run -p fabro-server automations
|
||||
```
|
||||
|
||||
Expected: all focused Rust checks pass.
|
||||
|
||||
- [ ] Run the focused frontend checks:
|
||||
|
||||
```bash
|
||||
cd lib/packages/fabro-api-client && bun run typecheck
|
||||
cd apps/fabro-web && bun run typecheck
|
||||
```
|
||||
|
||||
Expected: generated client and web app typecheck.
|
||||
|
||||
- [ ] Search for leftover master-gate references:
|
||||
|
||||
```bash
|
||||
rg -n "automation\\.enabled|enabled_api_trigger\\(\\).*automation|Automation is disabled|automation is disabled|\\\"enabled\\\": true" \
|
||||
lib/crates/fabro-automation \
|
||||
lib/crates/fabro-server/tests/it/api/automations.rs \
|
||||
lib/crates/fabro-server/src/server/handler/automations.rs \
|
||||
lib/crates/fabro-api/tests/automation_round_trip.rs \
|
||||
apps/fabro-web/app/components/automation-form.tsx \
|
||||
apps/fabro-web/app/routes/automations-new.tsx \
|
||||
apps/fabro-web/app/routes/automations-edit.tsx \
|
||||
apps/fabro-web/app/routes/automation-detail.tsx \
|
||||
apps/fabro-web/app/routes/automations.tsx
|
||||
```
|
||||
|
||||
Expected: no hits for the removed top-level automation enabled gate. Hits for trigger-level `enabled` are acceptable when they are clearly on `AutomationTrigger`, `ApiTrigger`, or `ScheduleTrigger`.
|
||||
|
||||
- [ ] Optional formatting check:
|
||||
|
||||
```bash
|
||||
cargo +nightly-2026-04-14 fmt --check --all
|
||||
```
|
||||
|
||||
Expected: Rust formatting passes. If it fails on touched Rust files, run `cargo +nightly-2026-04-14 fmt --all` and re-run the focused Rust checks.
|
||||
|
||||
## Explicit Assumptions
|
||||
|
||||
- No migration or compatibility parser is added for top-level automation `enabled`.
|
||||
- Existing automation TOML files that still contain top-level `enabled` are obsolete and may fail startup until manually edited.
|
||||
- Trigger-level `enabled` remains public API and persisted TOML.
|
||||
- API/manual run creation remains controlled by the enabled `api` trigger only.
|
||||
- Schedule execution, cron semantics, and schedule-trigger preservation are outside this cleanup.
|
||||
|
||||
|
||||
## Completed stages
|
||||
- **toolchain**: succeeded
|
||||
- Script: `command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1`
|
||||
- Output:
|
||||
```
|
||||
cargo 1.95.0 (f2d3ce0bd 2026-03-21)
|
||||
```
|
||||
- **preflight_compile**: succeeded
|
||||
- Script: `cargo check -q --workspace 2>&1`
|
||||
- Output: (empty)
|
||||
- **preflight_lint**: succeeded
|
||||
- Script: `cargo +nightly-2026-04-14 clippy -q --workspace --all-targets -- -D warnings 2>&1`
|
||||
- Output: (empty)
|
||||
- **implement**: failed
|
||||
- **simplify_opus**: succeeded
|
||||
- Model: claude-opus-4-7, 13.7k tokens in / 3.1k out
|
||||
- **simplify_gpt**: failed
|
||||
- **verify**: failed
|
||||
- Script: `git fetch origin main 2>&1 && git merge --no-edit --no-stat origin/main 2>&1 && cargo +nightly-2026-04-14 fmt --all 2>&1 && cargo dev docs refresh 2>&1 && cargo +nightly-2026-04-14 fmt --check --all 2>&1 && { command -v rg >/dev/null 2>&1 || { echo 'rg is required for verify'; exit 127; }; } && ! rg -n 'AuthMode::Disabled|RunAuthMethod|RunSubjectProvenance|\bActorRef\b|\bActorKind\b|AuthenticatedSubject|AuthenticatedService|AuthorizeRunScoped|AuthorizeRunBlob|AuthorizeStageArtifact|AuthorizeCommandLog|auth_method\s*==\s*"disabled"' lib/crates apps lib/packages docs/public/api-reference/fabro-api.yaml 2>&1 && cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings 2>&1 && cargo nextest run --workspace --status-level slow --profile ci 2>&1 && cargo dev docs check 2>&1 && bun install --frozen-lockfile 2>&1 && (cd apps/fabro-web && bun run typecheck) 2>&1 && (cd apps/fabro-web && bun run test) 2>&1 && (cd lib/packages/fabro-api-client && bun run typecheck) 2>&1 && cargo dev build -- -p fabro-cli --release 2>&1`
|
||||
- Output:
|
||||
```
|
||||
From https://github.com/fabro-sh/fabro
|
||||
* branch main -> FETCH_HEAD
|
||||
merge: origin/main - not something we can merge
|
||||
```
|
||||
|
||||
## Context
|
||||
- failure_class: deterministic
|
||||
- failure_signature: verify|deterministic|script failed with exit code: <n> ## output from https://github.com/fabro-sh/fabro * branch main -> fetch_head merge: origin/main - not something we can merge
|
||||
|
||||
|
||||
The verify step failed. Read the build output from context and fix all format, clippy, Rust test, docs, TypeScript typecheck/test, and build failures.
|
||||
5
stages/009-fixup@1/provider_used.json
Normal file
5
stages/009-fixup@1/provider_used.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"mode": "agent",
|
||||
"provider": "anthropic",
|
||||
"model": "claude-opus-4-7"
|
||||
}
|
||||
16
stages/009-fixup@1/response.md
Normal file
16
stages/009-fixup@1/response.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
No leftover auth-mode references. Everything passes:
|
||||
|
||||
- **Root cause**: The local git clone had a narrow fetch refspec (`feat/settings-environments-crud` only), so `git fetch origin main` only updated `FETCH_HEAD` without creating `refs/remotes/origin/main`, making `git merge origin/main` fail.
|
||||
- **Fix**: Added a `fetch = +refs/heads/main:refs/remotes/origin/main` line to `.git/config`'s `[remote "origin"]` so `origin/main` becomes a real remote-tracking branch.
|
||||
|
||||
After that fix, the full verify pipeline succeeds end-to-end:
|
||||
- Merge from `origin/main` (clean ort-strategy merge of Cargo.lock and two server files)
|
||||
- `cargo fmt --check --all` clean
|
||||
- `cargo dev docs refresh`/`check` clean
|
||||
- `cargo clippy --workspace --all-targets -D warnings` clean
|
||||
- `cargo nextest run --workspace --profile ci`: 6494 passed, 181 skipped
|
||||
- `bun install --frozen-lockfile` ok
|
||||
- `apps/fabro-web` `bun run typecheck` and `bun run test`: 508 pass
|
||||
- `lib/packages/fabro-api-client` `bun run typecheck` clean
|
||||
- `cargo dev build -- -p fabro-cli --release` succeeds
|
||||
- Auth-mode grep returns no leftovers
|
||||
Loading…
Add table
Reference in a new issue