|
| 1 | +--- |
| 2 | +phase: 12-builtin-ergonomics |
| 3 | +verified: 2026-03-15T20:05:00Z |
| 4 | +status: passed |
| 5 | +score: 10/10 must-haves verified |
| 6 | +re_verification: false |
| 7 | +--- |
| 8 | + |
| 9 | +# Phase 12: Builtin Ergonomics Verification Report |
| 10 | + |
| 11 | +**Phase Goal:** Ergonomic helpers for common Crossplane patterns — external_name annotation injection and skip_resource observability. |
| 12 | +**Verified:** 2026-03-15T20:05:00Z |
| 13 | +**Status:** passed |
| 14 | +**Re-verification:** No — initial verification |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## Goal Achievement |
| 19 | + |
| 20 | +### Observable Truths |
| 21 | + |
| 22 | +| # | Truth | Status | Evidence | |
| 23 | +|----|-------|--------|----------| |
| 24 | +| 1 | `Resource('x', body, external_name='my-name')` produces desired state with `crossplane.io/external-name` annotation set to `'my-name'` | VERIFIED | `injectExternalName` called in `resourceFn` after `PlainDictToStruct`; `TestCollector_ExternalName_Basic` passes | |
| 25 | +| 2 | `Resource('x', body)` without `external_name` kwarg produces desired state with no injected annotation | VERIFIED | Guard `if externalNameVal != nil` in `resourceFn`; `TestCollector_ExternalName_Omitted` passes | |
| 26 | +| 3 | `Resource('x', body, external_name='')` returns an error | VERIFIED | Empty-string check returns `"must not be empty"` error; `TestCollector_ExternalName_EmptyString` passes | |
| 27 | +| 4 | `Resource` with `external_name` and empty body auto-creates `metadata.annotations` path | VERIFIED | `getOrCreateNestedStruct` helper creates path; `TestCollector_ExternalName_EmptyBody` passes | |
| 28 | +| 5 | `Resource` with `external_name` kwarg AND manual `crossplane.io/external-name` annotation: kwarg wins, Warning event emitted | VERIFIED | `injectExternalName` detects conflict, appends `Warning` event to `cc.events`; `TestCollector_ExternalName_Conflict` passes | |
| 29 | +| 6 | `skip_resource('audit-logs', 'encryption disabled')` returns `None` | VERIFIED | `skipResourceFn` returns `starlark.None`; `TestCollector_SkipResource_ReturnsNone` passes | |
| 30 | +| 7 | After `skip_resource` call, `'audit-logs'` does NOT appear in desired state output | VERIFIED | `skipped` map tracked separately from `resources`; `TestCollector_SkipResource_NotInResources` passes | |
| 31 | +| 8 | `skip_resource` emits a Warning event with format: `Skipping resource 'audit-logs': encryption disabled` | VERIFIED | `fmt.Sprintf("Skipping resource %q: %s", name, reason)` with `Severity: "Warning"`, `Target: "Composite"`; `TestCollector_SkipResource_Warning` passes | |
| 32 | +| 9 | Calling `skip_resource` after `Resource()` for the same name errors with `'resource X already emitted, cannot skip'` | VERIFIED | `c.resources[name]` check in `skipResourceFn`; `TestCollector_SkipResource_AfterEmit` passes | |
| 33 | +| 10 | Calling `skip_resource` twice for same name: first call emits Warning, second is silent no-op | VERIFIED | `c.skipped[name]` dedup guard; `TestCollector_SkipResource_Dedup` passes | |
| 34 | + |
| 35 | +**Score:** 10/10 truths verified |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +### Required Artifacts |
| 40 | + |
| 41 | +| Artifact | Expected | Status | Details | |
| 42 | +|----------|----------|--------|---------| |
| 43 | +| `builtins/collector.go` | `external_name` kwarg handling, `getOrCreateNestedStruct`, `injectExternalName`, `externalNameAnnotation` constant | VERIFIED | All four present; `externalNameAnnotation = "crossplane.io/external-name"` at line 16; `getOrCreateNestedStruct` at line 274; `injectExternalName` at line 288 | |
| 44 | +| `builtins/collector.go` | `skip_resource` builtin: `skipped` map, `SkipResourceBuiltin` method, `skipResourceFn` | VERIFIED | `skipped map[string]bool` in `Collector` struct (line 72); `SkipResourceBuiltin` at line 97; `skipResourceFn` at line 104 | |
| 45 | +| `builtins/collector_test.go` | Tests for ERGO-01/ERGO-02 behaviors (`TestCollector_ExternalName*`) | VERIFIED | 8 `TestCollector_ExternalName_*` tests present (lines 619-1053); all pass | |
| 46 | +| `builtins/collector_test.go` | Tests for ERGO-03/ERGO-04 behaviors (`TestCollector_SkipResource*`) | VERIFIED | 7 `TestCollector_SkipResource_*` tests present (lines 840-1008); all pass | |
| 47 | +| `builtins/builtins.go` | `skip_resource` registered in `BuildGlobals` `StringDict` | VERIFIED | `"skip_resource": collector.SkipResourceBuiltin()` at line 81 | |
| 48 | +| `builtins/builtins_test.go` | `TestBuildGlobals_Keys` includes `skip_resource` in expected list | VERIFIED | `"skip_resource"` in `expected` slice; 15 globals confirmed | |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +### Key Link Verification |
| 53 | + |
| 54 | +| From | To | Via | Status | Details | |
| 55 | +|------|----|-----|--------|---------| |
| 56 | +| `collector.go:resourceFn` | `collector.go:injectExternalName` | Called after `PlainDictToStruct` when `externalNameVal != nil` | WIRED | `injectExternalName(s, string(en), name, c.cc)` at line 209 | |
| 57 | +| `collector.go:injectExternalName` | `ConditionCollector.events` | Appends `CollectedEvent` on conflict via `cc.mu.Lock()` | WIRED | `cc.mu.Lock(); cc.events = append(...)` at lines 296-300 | |
| 58 | +| `builtins.go:BuildGlobals` | `collector.go:SkipResourceBuiltin` | `collector.SkipResourceBuiltin()` registered as `"skip_resource"` in `StringDict` | WIRED | `"skip_resource": collector.SkipResourceBuiltin()` at line 81 | |
| 59 | +| `collector.go:SkipResourceBuiltin` | `ConditionCollector.events` | Emits `Warning` event on first skip via `cc.mu.Lock()` | WIRED | `c.cc.mu.Lock(); c.cc.events = append(...)` at lines 133-137 | |
| 60 | +| `collector.go:SkipResourceBuiltin` | `collector.go:resources` | Checks `c.resources[name]` to error on skip-after-emit | WIRED | `if _, exists := c.resources[name]; exists { ... }` at line 118 | |
| 61 | +| `fn.go:RunFunction` | `ConditionCollector.Events()` | `ApplyEvents(rsp, condCollector.Events())` at line 247 routes skip_resource warnings to response | WIRED | Warning events collected into `condCollector` flow through `ApplyEvents` pipeline | |
| 62 | +| `fn.go:RunFunction` | `NewCollector(condCollector)` | `collector := builtins.NewCollector(condCollector)` at line 90 | WIRED | `condCollector` passed at construction; enables cross-collector event routing | |
| 63 | + |
| 64 | +--- |
| 65 | + |
| 66 | +### Requirements Coverage |
| 67 | + |
| 68 | +| Requirement | Source Plan | Description | Status | Evidence | |
| 69 | +|-------------|------------|-------------|--------|----------| |
| 70 | +| ERGO-01 | 12-01 | User can set external-name annotation via `external_name` kwarg on `Resource()` | SATISFIED | `external_name??` in `UnpackArgs`; `injectExternalName` sets annotation; 8 tests pass | |
| 71 | +| ERGO-02 | 12-01 | User receives conflict warning when `external_name` kwarg and manual annotation both set | SATISFIED | Conflict detection in `injectExternalName` emits `Warning` event; `TestCollector_ExternalName_Conflict` verifies message format | |
| 72 | +| ERGO-03 | 12-02 | User can skip resource creation with `skip_resource(name, reason)` builtin | SATISFIED | `SkipResourceBuiltin` on `Collector`; registered in `BuildGlobals`; error on skip-after-emit; dedup working | |
| 73 | +| ERGO-04 | 12-02 | Skipped resources emit Warning event with reason visible in XR events | SATISFIED | `skipResourceFn` emits `{Severity: "Warning", Message: "Skipping resource ...", Target: "Composite"}`; flows through `ApplyEvents` pipeline in `fn.go` | |
| 74 | + |
| 75 | +All 4 ERGO requirements are satisfied. No orphaned requirements found. |
| 76 | + |
| 77 | +--- |
| 78 | + |
| 79 | +### Anti-Patterns Found |
| 80 | + |
| 81 | +None. No TODO/FIXME/HACK/placeholder comments, no empty implementations, no stub return patterns found in any modified file. |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +### Human Verification Required |
| 86 | + |
| 87 | +None. All behaviors are verifiable programmatically via unit tests, and the full test suite passes. |
| 88 | + |
| 89 | +--- |
| 90 | + |
| 91 | +### Gaps Summary |
| 92 | + |
| 93 | +No gaps. All 10 observable truths are verified, all 6 key artifacts are substantive and wired, all 7 key links are confirmed, and all 4 ERGO requirements are satisfied. |
| 94 | + |
| 95 | +**Full test suite result:** All packages pass with 0 failures. |
| 96 | + |
| 97 | +``` |
| 98 | +ok github.com/wompipomp/function-starlark 0.692s |
| 99 | +ok github.com/wompipomp/function-starlark/builtins 1.107s |
| 100 | +ok github.com/wompipomp/function-starlark/convert 0.794s |
| 101 | +ok github.com/wompipomp/function-starlark/runtime 0.225s |
| 102 | +ok github.com/wompipomp/function-starlark/runtime/oci 1.236s |
| 103 | +ok github.com/wompipomp/function-starlark/stdlib 0.343s |
| 104 | +``` |
| 105 | + |
| 106 | +--- |
| 107 | + |
| 108 | +_Verified: 2026-03-15T20:05:00Z_ |
| 109 | +_Verifier: Claude (gsd-verifier)_ |
0 commit comments