From c01e20ae974ca157fd267b28f3e05c7d67cbabfc Mon Sep 17 00:00:00 2001 From: Rodrigo Vicente Date: Wed, 7 Oct 2026 15:02:08 -0600 Subject: [PATCH] feat: edit says it amends the class it names (greenhouse decisions/0596) implement declares that it creates its named target, so a request that does not name the class is not asked about it; edit selects a class that exists, and is. The record of the lab's houses says what that question fell on: 28 of 34 times, a class the same session had brought into the house a moment before. edit now declares what it does: it amends, in place, a class that exists. The session's floor decides, from that session's own record, whether the class is one the session itself brought; this package runs no gate, so nothing changes here. The declaration was born in a later milpa/command than the oldest this package runs with. It is made around the contract, not inside it: where the installed Operation cannot carry it, edit is declared exactly as before and the floor keeps asking. --- src/Operations/DevToolsOperations.php | 40 ++++++++- .../AnEditAmendsTheClassItNamesTest.php | 82 +++++++++++++++++++ 2 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 tests/Operations/AnEditAmendsTheClassItNamesTest.php diff --git a/src/Operations/DevToolsOperations.php b/src/Operations/DevToolsOperations.php index 16329bc..b6fcc1c 100644 --- a/src/Operations/DevToolsOperations.php +++ b/src/Operations/DevToolsOperations.php @@ -356,7 +356,9 @@ public function operations(): array namedTarget: 'class', createsNamedTarget: true, ), - new Operation( + // AN EDIT AMENDS THE CLASS IT NAMES (greenhouse decisions/0596): declared around the contract, not + // inside it, because the oldest milpa/command this package runs with cannot carry the declaration. + self::amendingItsNamedTarget(new Operation( name: 'edit', effects: new EffectProfile( Mutation::Persistent, @@ -396,9 +398,13 @@ public function operations(): array 'required' => ['plugin', 'class', 'edits'], ], mutating: true, - // Same contract as implement: the target is THE CLASS, named by the human. + // Same contract as implement: the target is THE CLASS, named by the human — or, since greenhouse + // decisions/0596, by the session's own record of where that class came from. The record of the + // lab's houses: of 34 times a house asked a person to confirm an `edit`, 28 were about a class the + // same session had brought into the house. `edit` declares what it does — it amends a class that + // exists — and the session's floor reads the rest from facts. It still never creates one. namedTarget: 'class', - ), + )), new Operation( name: 'test', effects: new EffectProfile( @@ -720,4 +726,32 @@ public function operations(): array ), ]; } + /** + * The same operation, declaring that it amends the target it names — where the installed contract can carry it. + * + * `amendsNamedTarget` was born in a later milpa/command than the oldest this package runs with, and this + * `src/` travels with whatever vendor its owner has: a named argument the installed `Operation` does not know + * is a fatal error at the moment the catalogue is built. Where the contract cannot carry it, the operation is + * returned as it was declared and the session's floor keeps asking — the fail-closed answer an older house + * wants anyway. + */ + private static function amendingItsNamedTarget(Operation $operation): Operation + { + if (!self::contractCarries('amendsNamedTarget')) { + return $operation; + } + + return new Operation(...array_replace(get_object_vars($operation), ['amendsNamedTarget' => true])); + } + + /** + * Whether the installed `Operation` has that public property. + * + * The name arrives as a plain string on purpose: static analysis sees the milpa/command installed HERE and + * would rule the question settled, while this code runs against the one its owner installed. + */ + private static function contractCarries(string $property): bool + { + return property_exists(Operation::class, $property); + } } diff --git a/tests/Operations/AnEditAmendsTheClassItNamesTest.php b/tests/Operations/AnEditAmendsTheClassItNamesTest.php new file mode 100644 index 0000000..983b5e4 --- /dev/null +++ b/tests/Operations/AnEditAmendsTheClassItNamesTest.php @@ -0,0 +1,82 @@ +needsAContractThatCanSayIt(); + + $edit = $this->operations()['edit']; + + self::assertTrue($edit->amendsNamedTarget); + self::assertSame('class', $edit->namedTarget, 'and the target it speaks of is the class'); + self::assertFalse($edit->createsNamedTarget, 'amending is not creating: only `make` creates a class'); + } + + public function testImplementKeepsSayingItCreates(): void + { + $this->needsAContractThatCanSayIt(); + + $implement = $this->operations()['implement']; + + self::assertTrue($implement->createsNamedTarget); + self::assertFalse($implement->amendsNamedTarget, 'the two declarations are not the same statement'); + } + + public function testNothingElseInThisPackageSaysIt(): void + { + $this->needsAContractThatCanSayIt(); + + $amending = array_keys(array_filter($this->operations(), static fn (Operation $operation): bool => $operation->amendsNamedTarget)); + + self::assertSame(['edit'], $amending, 'an exception to the intent contract is declared one operation at a time'); + } + + public function testTheOperationsAreDeclaredWhateverTheInstalledContractCanSay(): void + { + $operations = $this->operations(); + + self::assertArrayHasKey('edit', $operations); + self::assertSame('class', $operations['edit']->namedTarget, 'the intent contract `edit` always had'); + } + + /** @return array */ + private function operations(): array + { + return array_column((new DevToolsOperations())->operations(), null, 'name'); + } + + private function needsAContractThatCanSayIt(): void + { + if (!property_exists(Operation::class, 'amendsNamedTarget')) { + self::markTestSkipped('The installed milpa/command cannot carry amendsNamedTarget (greenhouse decisions/0596): `edit` is declared as before, and the floor keeps asking.'); + } + } +}