Skip to content

refactor(clickhouse): make retention a readonly constructor property#129

Open
levivannoort wants to merge 2 commits into
mainfrom
feat/retention-ttl
Open

refactor(clickhouse): make retention a readonly constructor property#129
levivannoort wants to merge 2 commits into
mainfrom
feat/retention-ttl

Conversation

@levivannoort

Copy link
Copy Markdown
Contributor

What

Follow-up to #128. Converts the ClickHouse retention config from a getRetention()/setRetention() accessor pair to a promoted public readonly ?int $retention constructor property.

  • Positive-days validation moves into the constructor body (same message, same behavior).
  • The fluent setter is dropped; retention is now set once at construction.

Why

Readonly-after-construction is coroutine-safe — no mid-flight mutation of adapter config. Aligns with the style we're standardizing across codebases.

Notes

Internal $this->retention usage in setup() is unchanged. Retention tests now build the adapter via the constructor and assert on the property.

🤖 Generated with Claude Code

Replace the getRetention/setRetention accessors with a promoted
public readonly ?int constructor property. The positive-days check
moves into the constructor body. Immutable-after-construction is
coroutine-safe; the fluent setter is dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR converts the ClickHouse adapter's retention field from a private property with getRetention()/setRetention() accessors to a promoted public readonly ?int $retention constructor parameter, with validation extracted to a private validateRetention() helper. However, setRetention() was not removed — it still exists and assigns to the now-readonly property, causing a PHP Fatal Error on every call.

  • setRetention() (line 366–371) writes $this->retention = $retention after construction; PHP 8.1+ will always throw \\Error: Cannot modify readonly property ClickHouse::$retention here.
  • testSetRetention calls setRetention(30) on an already-constructed object, so the test itself errors before any assertion runs.
  • The PR description says "the fluent setter is dropped" but neither the source method nor the test that exercises it were removed.

Confidence Score: 1/5

Not safe to merge — setRetention() modifies a readonly property and will throw a PHP Fatal Error on every call.

The PR leaves a public method (setRetention) that unconditionally writes to a readonly property. Any caller that invokes it — including the test suite — will receive a PHP \Error rather than the expected behavior. The bug affects both the production adapter and the tests, and directly contradicts the PR’s stated goal.

src/Audit/Adapter/ClickHouse.php (remove or fix setRetention) and tests/Audit/Adapter/ClickHouseTest.php (remove or update testSetRetention).

Important Files Changed

Filename Overview
src/Audit/Adapter/ClickHouse.php Promotes retention to a public readonly constructor property and adds validateRetention(), but leaves setRetention() intact — that method assigns to the now-readonly property and will throw a PHP Fatal Error on any call.
tests/Audit/Adapter/ClickHouseTest.php Tests are updated to assert on the constructor-promoted property, but testSetRetention still calls setRetention() post-construction, which will always throw before any assertion reaches the test runner.

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
src/Audit/Adapter/ClickHouse.php:366-371
**`setRetention()` writes to a `readonly` property — PHP Fatal Error**

`$retention` is declared `public readonly ?int $retention` at line 102. PHP does not permit re-assignment of a `readonly` property after object construction; any call to `setRetention()` will throw `\Error: Cannot modify readonly property ClickHouse::$retention`. The PR description states "the fluent setter is dropped", but the method was left in. It needs to be removed (or the `readonly` modifier removed from the property if the setter is intentional).

### Issue 2 of 2
tests/Audit/Adapter/ClickHouseTest.php:407-420
**Test calls the broken setter — will always error before any assertion**

`testSetRetention` invokes `$adapter->setRetention(30)` on an already-constructed object whose `$retention` is `readonly`. This immediately throws `\Error: Cannot modify readonly property ClickHouse::$retention`, so none of the assertions below that line are ever reached. If `setRetention()` is removed (the PR's stated intent), this entire test block should be removed. If the setter is kept (and `readonly` dropped), the test is correct as-is.

Reviews (2): Last reviewed commit: "feat(clickhouse): make retention settabl..." | Re-trigger Greptile

A single adapter instance runs setup() against several tables by mutating
its namespace between calls (e.g. a shared `projects` table with a short
window and a `console` table with a long one). A readonly, construction-time
retention forced the same TTL onto every table. Drop `readonly`, add a
fluent `setRetention()` so the window can be set per table before each
setup(), and share validation via validateRetention().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment on lines +366 to 371
public function setRetention(?int $retention): self
{
return $this->asyncCleanup;
$this->validateRetention($retention);
$this->retention = $retention;
return $this;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 setRetention() writes to a readonly property — PHP Fatal Error

$retention is declared public readonly ?int $retention at line 102. PHP does not permit re-assignment of a readonly property after object construction; any call to setRetention() will throw \Error: Cannot modify readonly property ClickHouse::$retention. The PR description states "the fluent setter is dropped", but the method was left in. It needs to be removed (or the readonly modifier removed from the property if the setter is intentional).

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Audit/Adapter/ClickHouse.php
Line: 366-371

Comment:
**`setRetention()` writes to a `readonly` property — PHP Fatal Error**

`$retention` is declared `public readonly ?int $retention` at line 102. PHP does not permit re-assignment of a `readonly` property after object construction; any call to `setRetention()` will throw `\Error: Cannot modify readonly property ClickHouse::$retention`. The PR description states "the fluent setter is dropped", but the method was left in. It needs to be removed (or the `readonly` modifier removed from the property if the setter is intentional).

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

Comment on lines 407 to 420
username: 'default',
password: 'clickhouse'
);

$adapter->setRetention(30);
$this->assertSame($adapter, $adapter->setRetention(30));
$this->assertEquals(30, $adapter->retention);

$adapter->setRetention(null);
$this->assertNull($adapter->getRetention());
$this->assertNull($adapter->retention);

$this->expectException(Exception::class);
$this->expectExceptionMessage('Retention must be a positive number of days');
$adapter->setRetention(0);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Test calls the broken setter — will always error before any assertion

testSetRetention invokes $adapter->setRetention(30) on an already-constructed object whose $retention is readonly. This immediately throws \Error: Cannot modify readonly property ClickHouse::$retention, so none of the assertions below that line are ever reached. If setRetention() is removed (the PR's stated intent), this entire test block should be removed. If the setter is kept (and readonly dropped), the test is correct as-is.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/Audit/Adapter/ClickHouseTest.php
Line: 407-420

Comment:
**Test calls the broken setter — will always error before any assertion**

`testSetRetention` invokes `$adapter->setRetention(30)` on an already-constructed object whose `$retention` is `readonly`. This immediately throws `\Error: Cannot modify readonly property ClickHouse::$retention`, so none of the assertions below that line are ever reached. If `setRetention()` is removed (the PR's stated intent), this entire test block should be removed. If the setter is kept (and `readonly` dropped), the test is correct as-is.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants