Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c2bae2f
test(#135): add unit tests for InvoiceCalculator and QuoteCalculator
claude Jun 14, 2026
2b22da9
test(#135): add AAA comments, edge cases, and failing path tests to c…
claude Jun 14, 2026
f07a5d4
style(#135): use /* Arrange/Act/Assert */ block comments in calculato…
claude Jun 14, 2026
ada1c27
Fable http client
nielsdrost7 Jul 3, 2026
a396028
Fully Functional Fable5 Automation system
nielsdrost7 Jul 3, 2026
68d8fad
Improvements
nielsdrost7 Jul 3, 2026
36b83c1
Improvements
nielsdrost7 Jul 3, 2026
408aac2
Improvements
nielsdrost7 Jul 3, 2026
5bc2a0e
Fable Test Automation Improvements
nielsdrost7 Jul 3, 2026
d2b0c31
ran pint
nielsdrost7 Jul 3, 2026
c616368
Fable 5 test automation improvements
nielsdrost7 Jul 3, 2026
bae391f
Fable 5 test automation improvements
nielsdrost7 Jul 3, 2026
368f9a8
remove IDE files from repository
nielsdrost7 Jul 3, 2026
34c4bc4
Fable 5 test automation improvements
nielsdrost7 Jul 3, 2026
0d1e7b6
Fable 5 test automation improvements
nielsdrost7 Jul 3, 2026
f808e9a
Fable 5 test automation improvements
nielsdrost7 Jul 3, 2026
87ab88f
Fable 5 test automation improvements
nielsdrost7 Jul 3, 2026
406d9db
Test honesty improvements
nielsdrost7 Jul 3, 2026
f8f91dd
Fable 5 test automation improvements
nielsdrost7 Jul 3, 2026
487f62c
fix(tests): seed roles/permissions in panel test base classes
nielsdrost7 Jul 3, 2026
1853508
fix(tests): restore company crud permissions
nielsdrost7 Jul 3, 2026
5fb26a9
style: apply Laravel Pint fixes
github-actions[bot] Jul 3, 2026
3ea15da
improve .gitignore
nielsdrost7 Jul 3, 2026
aa24901
improve .gitignore
nielsdrost7 Jul 3, 2026
7ed196c
Merge remote-tracking branch 'origin/develop' into feature/135-calcul…
nielsdrost7 Jul 4, 2026
b800348
fix(#135): accept object items in AbstractCalculator accessors
nielsdrost7 Jul 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .claude/fable5/FABLE5_EXECUTION_PRD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
FABLE5 AUTONOMOUS EXECUTION PRD
InvoicePlane-v2

────────────────────────────────────────
PURPOSE
────────────────────────────────────────
Fable5 processes GitHub issues into draft PRs while reusing existing branches from:
underdogg-forks/invoiceplane-v2

PRs already exist in:
invoiceplane/invoiceplane-v2

Branches already exist in:
underdogg-forks/invoiceplane-v2

Fable5 must reconcile both systems.

────────────────────────────────────────
CRITICAL RULE
────────────────────────────────────────
NEVER CREATE NEW BRANCHES IF A PR-BOUND BRANCH ALREADY EXISTS.

Always reuse:
- existing PR branches
- existing fork branches

Branch identity is authoritative.

────────────────────────────────────────
SOURCE OF TRUTH PRIORITY
────────────────────────────────────────
1. Existing GitHub PR (invoiceplane/invoiceplane-v2)
2. Existing branch in fork (underdogg-forks/invoiceplane-v2)
3. Issue definition
4. Repository code state

────────────────────────────────────────
EXECUTION MODEL
────────────────────────────────────────
- Iterate through all provided issue IDs
- For each issue:
- locate existing PR
- extract associated branch from fork
- checkout and continue work on that branch
- do NOT reinitialize branch

────────────────────────────────────────
BRANCH REUSE RULE
────────────────────────────────────────
If PR exists:
- fetch PR branch from upstream or fork
- checkout branch locally
- continue commits

If PR does NOT exist:
- only then create new branch

────────────────────────────────────────
COMMIT POLICY
────────────────────────────────────────
- frequent commits required
- atomic logical changes only
- never mix multiple issues unless explicitly grouped

────────────────────────────────────────
PR POLICY
────────────────────────────────────────
- all PRs must remain DRAFT
- PR title format:
[IP-{issueId}] description
- PR body must be updated, never replaced blindly
- preserve GitHub discussion history

────────────────────────────────────────
FAILURE HANDLING
────────────────────────────────────────
If branch cannot be found:
- attempt fetch from:
underdogg-forks/invoiceplane-v2
- if still missing:
skip issue and log reason

────────────────────────────────────────
EXECUTION END CONDITION
────────────────────────────────────────
Stop when:
- all issues processed OR skipped
37 changes: 37 additions & 0 deletions .claude/fable5/Fable5PolicyLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

final class Fable5PolicyLoader
{
public function load(): array
{
return [
'prd' => $this->loadFile('.claude/fable5/FABLE5_EXECUTION_PRD.md'),
'skills' => $this->loadDirectory('.claude/fable5/skills'),
'runtime' => $this->loadFile('.claude/fable5/runtime/overrides.md'),
'repo' => $this->loadFile('CLAUDE.md'),
];
}

private function loadFile(string $path): array
{
return file_exists($path)
? [file_get_contents($path)]
: [];
}

private function loadDirectory(string $path): array
{
if (!is_dir($path)) {
return [];
}

$files = glob($path . '/*.md');

return array_map(
fn ($file) => file_get_contents($file),
$files
);
}
}
75 changes: 75 additions & 0 deletions .claude/fable5/prd/EXECUTION_BOOT_FLOW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
FABLE5 EXECUTION BOOT FLOW

────────────────────────────────────────
PHASE 0 — SYSTEM INITIALIZATION
────────────────────────────────────────
Before any issue execution begins, Fable5 MUST build a deterministic execution graph.

This step is mandatory and must complete successfully before any branch work starts.

────────────────────────────────────────
PHASE 1 — DATA COLLECTION
────────────────────────────────────────
Fetch the following sources:

1. All open PRs from:
invoiceplane/invoiceplane-v2

2. All branches from:
underdogg-forks/invoiceplane-v2

3. Input issue list (static execution payload)

────────────────────────────────────────
PHASE 2 — RECONCILIATION
────────────────────────────────────────
Build an ExecutionGraph by mapping:

Issue ID →
Existing PR →
Associated branch (if available) →
Fork branch state

Rules:

- If PR exists AND branch exists in fork:
→ mark node as EXISTING_PR

- If PR exists BUT branch missing:
→ mark node as PR_MISSING_BRANCH

- If branch exists BUT no PR:
→ mark node as ORPHAN_BRANCH

- If neither exists:
→ mark node as NEW

────────────────────────────────────────
PHASE 3 — EXECUTION STRATEGY GENERATION
────────────────────────────────────────
Fable5 MUST derive execution order from graph:

Priority order:
1. EXISTING_PR (reuse and continue work)
2. ORPHAN_BRANCH (recover and attach to PR if needed)
3. PR_MISSING_BRANCH (repair state)
4. NEW (create fresh branches)

────────────────────────────────────────
PHASE 4 — PARALLELIZATION PLAN
────────────────────────────────────────
Fable5 may execute branches in parallel only if:

- no shared module writes exist
- no overlapping DTO / Service modifications occur

Otherwise execution must be serialized per module lock rules.

────────────────────────────────────────
PHASE 5 — EXECUTION HANDOFF
────────────────────────────────────────
Only after graph is complete:

→ begin issue processing loop
→ reuse branches from graph
→ never recreate existing execution state
7 changes: 7 additions & 0 deletions .claude/fable5/runtime/overrides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
RUNTIME OVERRIDES

- allow_reuse_existing_branches=true
- forbid_branch_recreation=true
- execution_mode=continuous
- concurrency=enabled
- commit_frequency=high
26 changes: 26 additions & 0 deletions .claude/fable5/skills/concurrency.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
CONCURRENCY RULES

────────────────────────────────────────
PARALLEL EXECUTION
────────────────────────────────────────
Allowed only when:
- branches belong to different PRs
- no shared module writes

────────────────────────────────────────
MODULE LOCKING
────────────────────────────────────────
A module is locked when:
- a branch is actively modifying it

No concurrent edits allowed on:
- same Service
- same DTO
- same Filament Resource

────────────────────────────────────────
SAFE PARALLEL MODEL
────────────────────────────────────────
Each PR branch is an isolated execution unit.

No cross-branch writes to same module.
29 changes: 29 additions & 0 deletions .claude/fable5/skills/git-reuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
PR + BRANCH REUSE POLICY

────────────────────────────────────────
CORE PRINCIPLE
────────────────────────────────────────
Existing work is authoritative.

If a branch exists in:
underdogg-forks/invoiceplane-v2

and is linked to a PR in:
invoiceplane/invoiceplane-v2

it MUST be reused.

────────────────────────────────────────
MAPPING RULE
────────────────────────────────────────
Issue ID → PR → Branch → Fork repository state

This mapping is immutable during execution.

────────────────────────────────────────
NO DUPLICATION RULE
────────────────────────────────────────
Never:
- recreate PR branch
- reinitialize git history
- reapply already existing commits
34 changes: 34 additions & 0 deletions .claude/fable5/skills/git.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
GIT EXECUTION RULES

────────────────────────────────────────
BRANCH DISCOVERY
────────────────────────────────────────
Always resolve branches in this order:

1. GitHub PR branch reference
2. local fork (underdogg-forks/invoiceplane-v2)
3. remote origin fallback

Never create a branch if a PR-linked branch exists.

────────────────────────────────────────
BRANCH CHECKOUT RULE
────────────────────────────────────────
When PR exists:
- fetch PR head ref
- checkout exact branch
- continue history

No rebase unless explicitly required by issue.

────────────────────────────────────────
COMMIT RULES
────────────────────────────────────────
- atomic commits only
- one logical change per commit
- frequent commits required

────────────────────────────────────────
SAFETY RULE
────────────────────────────────────────
Never overwrite branch history that already belongs to a PR.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,8 @@ package-lock.json
*.sqlite
/failures.txt
/yarnpack.txt
/automation/.idea/
/automation/vendor/
/automation/test-honesty/vendor/
.claude/fable5/runtime/control.json
upd.sh
16 changes: 16 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,22 @@ DB_CONNECTION=sqlite
DB_DATABASE=:memory:
```

### AAA phase comment style

Phase labels (`Arrange`, `Act`, `Assert`) inside test methods **must** use block comments. Line comments (`//`) are **prohibited** for phase labels.

```php
/* Arrange */
...
/* Act */
...
/* Assert */

/* Act & Assert */ ← combined phase label, same rule
```

**Never** write `// Arrange`, `// Act`, or `// Assert`.

---

## Key model notes
Expand Down
1 change: 1 addition & 0 deletions Modules/Core/Database/Seeders/RolesSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ function ($p) use ($customerResources) {
$isBasicAction = str_starts_with($p, 'view-')
|| str_starts_with($p, 'create-')
|| str_starts_with($p, 'edit-')
|| str_starts_with($p, 'delete-')
|| str_starts_with($p, 'export-')
|| str_starts_with($p, 'duplicate-');
$isCustomerResource = (bool) array_filter(
Expand Down
6 changes: 3 additions & 3 deletions Modules/Core/Support/AbstractCalculator.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ public function updateAndSave($document, string $itemsRelation = 'items', array
*/
protected function calculateItemSubtotal($item): float
{
$quantity = (float) ($item['quantity'] ?? $item->quantity ?? 0);
$price = (float) ($item['price'] ?? $item->price ?? 0);
$quantity = (float) (is_array($item) ? ($item['quantity'] ?? 0) : ($item->quantity ?? 0));
$price = (float) (is_array($item) ? ($item['price'] ?? 0) : ($item->price ?? 0));

return $quantity * $price;
}
Expand All @@ -115,7 +115,7 @@ protected function calculateItemSubtotal($item): float
*/
protected function calculateItemTaxes($item, float $subtotal): array
{
$discount = (float) ($item['discount'] ?? $item->discount ?? 0);
$discount = (float) (is_array($item) ? ($item['discount'] ?? 0) : ($item->discount ?? 0));
$discountedSubtotal = max($subtotal - $discount, 0);

// Get tax rates from relationships if available, otherwise use 0
Expand Down
11 changes: 11 additions & 0 deletions Modules/Core/Tests/AbstractAdminPanelTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Carbon;
use Modules\Core\Database\Seeders\PermissionsSeeder;
use Modules\Core\Database\Seeders\RolesSeeder;
use Modules\Core\Enums\UserRole;
use Modules\Core\Models\Company;
use Modules\Core\Models\User;

Expand Down Expand Up @@ -34,6 +37,14 @@ protected function setUp(): void

session(['current_company_id' => $this->company->id]);

/*
* Admin resources gate every page on Spatie permissions (canViewAny
* etc.), so the test user needs the seeded super_admin permission set.
*/
(new PermissionsSeeder())->run();
(new RolesSeeder())->run();
$this->superAdmin->assignRole(UserRole::SUPER_ADMIN->value);

$this->withoutExceptionHandling();
}

Expand Down
Loading
Loading