@exaudeus/workrail 3.24.0 → 3.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/console/assets/index-BXRk3te_.css +1 -0
- package/dist/console/assets/{index-CWETdPGj.js → index-TMfptYpQ.js} +9 -9
- package/dist/console/index.html +2 -2
- package/dist/di/container.js +1 -1
- package/dist/infrastructure/session/HttpServer.js +11 -0
- package/dist/manifest.json +31 -23
- package/dist/mcp/transports/bridge-entry.d.ts +1 -0
- package/dist/mcp/transports/bridge-entry.js +93 -0
- package/dist/mcp-server.d.ts +1 -0
- package/dist/mcp-server.js +48 -16
- package/dist/v2/infra/local/session-lock/index.d.ts +3 -1
- package/dist/v2/infra/local/session-lock/index.js +18 -1
- package/dist/v2/usecases/console-service.js +71 -1
- package/dist/v2/usecases/console-types.d.ts +5 -0
- package/package.json +1 -1
- package/workflows/mercury-android.clickstream-implementation.json +205 -0
- package/workflows/mercury-ios.clickstream-implementation.json +193 -0
- package/workflows/rich-object-contribution.json +258 -0
- package/dist/console/assets/index-ByW7d9qr.css +0 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mercury-android.clickstream-implementation",
|
|
3
|
+
"name": "Mercury Android: Implement Feature Tracking",
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"description": "Guides an engineer through implementing clickstream analytics and/or telemetry for a mercury-android feature. Conditionally handles either or both: discovers clickstream events, defines taxonomy and telemetry types, wires MonitoringBus and ZgIlluminateTelemetryContract, and writes tests.",
|
|
6
|
+
"validatedAgainstSpecVersion": 3,
|
|
7
|
+
"about": "## Mercury Android: Implement Feature Tracking\n\nThis workflow handles clickstream analytics, operational telemetry, or both — using `runCondition` to skip steps that don't apply.\n\n### What it does\n\n1. Identifies which tracking types are needed (clickstream, telemetry, or both)\n2. Discovers the clickstream event spec from Glean or user input (clickstream only)\n3. Defines taxonomy constants and sealed event catalog (clickstream only)\n4. Defines telemetry event and error types (telemetry only)\n5. Wires the MonitoringBus — Variant A (clickstream only)\n6. Integrates tracking calls into the ViewModel\n7. Writes tests and runs a final verification barrier\n\n### Reference implementations\n\n- Clickstream: `features/messaging/modules/conversation-actions/impl/src/.../monitoring/`\n- Telemetry: `features/messaging/impl/src/.../telemetry/MessagingTelemetry.kt`\n\n### When to use it\n\nUse this workflow when adding any combination of clickstream events or telemetry instrumentation to a feature module.\n\n### What it produces\n\n**Clickstream:** taxonomy enum constants, sealed event catalog, MonitoringBus, MonitoringPublisher, AnalyticsObserver, DI module, FakeMonitoringPublisher tests\n\n**Telemetry:** `[Feature]Telemetry.kt` sealed types, `[Feature]TelemetryEventType` and `[Feature]TelemetryErrorType` enums, ZgIlluminateTelemetryContract injection and tests",
|
|
8
|
+
"examples": [
|
|
9
|
+
"Add clickstream tracking to the new listing alert feature",
|
|
10
|
+
"Add telemetry error tracking and transaction timing to the connection flow",
|
|
11
|
+
"Instrument the buyer connection request flow with both analytics and telemetry",
|
|
12
|
+
"Wire telemetry transaction timing for the conversation load operation"
|
|
13
|
+
],
|
|
14
|
+
"recommendedPreferences": {
|
|
15
|
+
"recommendedAutonomy": "guided",
|
|
16
|
+
"recommendedRiskPolicy": "balanced"
|
|
17
|
+
},
|
|
18
|
+
"preconditions": [
|
|
19
|
+
"The feature module exists and the ViewModel is already implemented.",
|
|
20
|
+
"Agent has read access to the codebase.",
|
|
21
|
+
"Glean MCP is available for clickstream event spec discovery (falls back to user input if not found)."
|
|
22
|
+
],
|
|
23
|
+
"metaGuidance": [
|
|
24
|
+
"REFERENCE IMPL: read features/messaging/modules/conversation-actions/impl/src/.../monitoring/ before writing any MonitoringBus code. Follow that structure.",
|
|
25
|
+
"PREFERRED PATTERN: Variant A — observers implement EventObserver<T> directly, bound via @Binds @IntoSet in @Module @ContributesTo. Use Variant B (Dagger marker interface) only when cross-module @ContributesMultibinding is genuinely required.",
|
|
26
|
+
"ANALYTICS BRIDGE: events needing clickstream implement AnalyticsCapable with a non-null analyticsModel. Analytics-silent events must NOT implement it. The AnalyticsObserver casts to AnalyticsCapable? — null is the correct silent path.",
|
|
27
|
+
"NO SILENT DROPS: never write 'as? [Type] ?: return' without a log statement. A silently dropped event has no observable symptom and will not surface in tests.",
|
|
28
|
+
"REDUCER PATTERN: prefer returning a [Feature]Action.TrackEvent([Feature]MonitoringEvent.X) from reduceActions() over imperative publish() calls. Pure reducer output is testable without coroutines or mocks.",
|
|
29
|
+
"TEST WITH FAKES: create a FakeMonitoringPublisher that accumulates published events in a list. Do not use mockk for this — fakes are more realistic and less brittle.",
|
|
30
|
+
"LAYER OWNERSHIP: the ViewModel injects MonitoringPublisher and calls publish(). Use cases and repositories do not own the MonitoringBus. They may use ZgIlluminateTelemetryContract directly for data-layer errors.",
|
|
31
|
+
"DI COMPLETENESS: every observer must have a @Binds @IntoSet binding in the feature's DI module. An unbound observer is silently ignored at runtime with no compile error.",
|
|
32
|
+
"TELEMETRY: inject ZgIlluminateTelemetryContract into the ViewModel or Repository. Call logEvent() for milestones, logException() for errors, transactionStart/Stop() for timing. Define types in [Feature]Telemetry.kt."
|
|
33
|
+
],
|
|
34
|
+
"assessments": [
|
|
35
|
+
{
|
|
36
|
+
"id": "build-correctness-gate",
|
|
37
|
+
"purpose": "The implementation compiles and all tests pass.",
|
|
38
|
+
"dimensions": [
|
|
39
|
+
{
|
|
40
|
+
"id": "build_correctness",
|
|
41
|
+
"purpose": "Build succeeds and tests pass. No compilation errors or failing assertions.",
|
|
42
|
+
"levels": ["low", "high"]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "invariant-preservation-gate",
|
|
48
|
+
"purpose": "Invariants captured in the understand step still hold in the implemented code.",
|
|
49
|
+
"dimensions": [
|
|
50
|
+
{
|
|
51
|
+
"id": "invariant_preservation",
|
|
52
|
+
"purpose": "Each named invariant has been verified in the implementation.",
|
|
53
|
+
"levels": ["low", "high"]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "implementation-gaps-gate",
|
|
59
|
+
"purpose": "A deliberate scan for gaps surfaced during implementation has been completed.",
|
|
60
|
+
"dimensions": [
|
|
61
|
+
{
|
|
62
|
+
"id": "implementation_gaps",
|
|
63
|
+
"purpose": "Active scan completed: gaps are fixed inline, filed as follow-up tickets, or explicitly deferred.",
|
|
64
|
+
"levels": ["low", "high"]
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"steps": [
|
|
70
|
+
{
|
|
71
|
+
"id": "understand-feature",
|
|
72
|
+
"title": "Understand the Feature",
|
|
73
|
+
"prompt": "Read the feature module you are adding tracking to.\n\nFind:\n- The ViewModel and Reducer or EventProcessor: what user events exist that should generate analytics?\n- Any existing `monitoring/` directory: does a MonitoringBus already exist (`*MonitoringBus.kt`)?\n- Any existing `analytics/` directory: are taxonomy enum constants already defined (`*AnalyticsConstants.kt`)?\n- The feature's public module for any existing analytics event interfaces\n\nAlso read the reference implementation now — you will follow this pattern:\n`features/messaging/modules/conversation-actions/impl/src/main/java/.../monitoring/`\n\nIdentify which user actions (taps, page loads, impressions) should generate clickstream events. Also identify whether any operations need operational telemetry: error paths worth tracking in Datadog, performance-critical operations worth timing as transactions, or key milestones worth logging.\n\nNote: clickstream is for product analytics (user behavior); telemetry is for operational health (errors, performance, Datadog).\n\nCapture:\n- `hasExistingMonitoringBus`: true if a `*MonitoringBus.kt` already exists in this feature\n- `hasExistingAnalyticsConstants`: true if taxonomy enum constants already exist for this feature\n- `featureModulePath`: root source directory for the feature impl\n- `featureBasePackage`: Java package for new files\n- `actionsToTrack`: list of action names needing clickstream events (e.g. [\"UserOpenedScreen\", \"UserTappedSendButton\"])\n- `invariants`: correctness rules that must hold (e.g. [\"Every actionsToTrack action maps to one MonitoringEvent subtype\", \"Every AnalyticsCapable event has non-null analyticsModel\", \"Every observer has @Binds @IntoSet\"])\n- `acceptanceCriteria`: what done looks like (e.g. [\"All events fire correctly when user acts\", \"FakeMonitoringPublisher test passes for each event\", \"DI module compiles clean\"])\n- `needsClickstream`: true if product analytics events are needed\n- `needsTelemetry`: true if operational telemetry is needed (errors, timings, transactions)\n- `telemetryEventsNeeded`: list of telemetry signals (e.g. [\"renderDuration transaction\", \"loadError error\", \"submitSuccess event\"])"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "discover-events",
|
|
77
|
+
"title": "Discover Clickstream Event Definitions",
|
|
78
|
+
"runCondition": { "var": "needsClickstream", "equals": true },
|
|
79
|
+
"prompt": "Find the analytics event spec for this feature.\n\nSearch Glean for event definitions. Try these queries in order until you find something useful:\n1. The ticket number (ACEI/ICEI) — check the session goal or `git log` for a reference\n2. \"[feature name] clickstream events\"\n3. \"[feature name] analytics event type\"\n4. \"[feature name] tracking spec\"\n\nA useful spec defines per event:\n- Event type ID (a 4-digit number, e.g. 5527)\n- Trigger location string (e.g. MESSAGING_INBOX)\n- Trigger source string (e.g. USER_ACTION)\n- Trigger object string (e.g. CONVERSATION_ITEM)\n- Semantic event string (e.g. CLICK, VIEW, IMPRESSION)\n- Template ID — one of: 186, 171, 211, 237, 247, 337 (from CommonTemplateId)\n- Category: page_view / interaction / impression\n\nIf Glean returns a document with these values, extract them for each action in `actionsToTrack`.\n\nIf no spec is found in Glean, tell the user:\n\n\"I could not find an analytics event spec for this feature in Glean. For each of the following actions [list actionsToTrack], please provide: (1) event type ID, (2) trigger location string, (3) trigger source string, (4) trigger object string, (5) semantic event string, (6) template ID (186/171/211/237/247/337), (7) category (page_view/interaction/impression).\"\n\nCapture:\n- `events`: array of {name, eventTypeId, triggerLocation, triggerSource, triggerObject, semanticEvent, templateId, category}\n- `eventsSource`: \"glean\" or \"user_provided\"",
|
|
80
|
+
"requireConfirmation": true
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"id": "define-events",
|
|
84
|
+
"title": "Define Taxonomy Constants and Event Catalog",
|
|
85
|
+
"runCondition": { "var": "needsClickstream", "equals": true },
|
|
86
|
+
"prompt": "Write the taxonomy enum constants and sealed event catalog for this feature.\n\nTaxonomy constants — follow the pattern in `MessagingAnalyticsConstants.kt`. Each enum implements the corresponding illuminate interface:\n\n```kotlin\nenum class [Feature]EventType(override val value: String) : EventType { /* one value per event */ }\nenum class [Feature]TriggerLocation(override val value: String) : TriggerLocation { ... }\nenum class [Feature]TriggerSource(override val value: String) : TriggerSource { ... }\nenum class [Feature]TriggerObject(override val value: String) : TriggerObject { ... }\nenum class [Feature]SemanticEvent(override val value: String) : SemanticEvent { ... }\n```\n\nSealed event catalog — each `data object` carries a pre-built `ZgIlluminateAnalyticsModel` using the enum constants above:\n\n```kotlin\nsealed interface [Feature]AnalyticsEvents {\n val analytics: ZgIlluminateAnalyticsModel\n sealed interface PageView : [Feature]AnalyticsEvents { ... }\n sealed interface Interaction : [Feature]AnalyticsEvents { ... }\n sealed interface Impression : [Feature]AnalyticsEvents { ... }\n}\n```\n\nIf events require contextual data beyond the base model (conversation ID, unread count, etc.), create `[Feature]ContextualData` implementing `ZgIlluminateContextualData` with the required fields.\n\nFor each entry in `events`, write a corresponding enum value in `[Feature]EventType`. Never use raw string literals for event type IDs — always go through the enum constants.",
|
|
87
|
+
"promptFragments": [
|
|
88
|
+
{
|
|
89
|
+
"id": "has-existing-constants",
|
|
90
|
+
"when": { "var": "hasExistingAnalyticsConstants", "equals": true },
|
|
91
|
+
"text": "Taxonomy constants already exist for this feature. Add new enum values to the existing files rather than creating new ones. Match the naming style already in use."
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"id": "define-telemetry-events",
|
|
97
|
+
"title": "Define Telemetry Types",
|
|
98
|
+
"runCondition": { "var": "needsTelemetry", "equals": true },
|
|
99
|
+
"prompt": "Define the telemetry event and error types for this feature.\n\nCreate `[Feature]Telemetry.kt` following the pattern in `features/messaging/impl/src/main/java/com/zillow/android/messaging/impl/telemetry/MessagingTelemetry.kt`.\n\nThe structure is an `object` containing nested sealed interfaces that extend `ZgIlluminateTelemetryType`:\n\n```kotlin\nobject [Feature]Telemetry {\n sealed interface Event : ZgIlluminateTelemetryType.Event {\n // No-arg milestone events use data object\n data object RenderCompleted : Event\n // Events with context use data class\n data class SubmitAttempted(val itemCount: Int) : Event\n }\n sealed interface Error : ZgIlluminateTelemetryType.Error {\n // Error subtypes must provide throwable\n data class LoadFailed(override val throwable: Throwable) : Error\n }\n}\n```\n\nOnly add an `Error` block if `telemetryEventsNeeded` includes error-type signals. Only add `Event` subtypes for event/transaction signals.\n\nIf Datadog attribution keys are needed (for dashboard filtering), also create:\n- `[Feature]TelemetryEventType.kt` — `enum class ... (override val value: String) : ZgIlluminateTelemetryEventType`\n- `[Feature]TelemetryErrorType.kt` — `enum class ... (override val value: String) : ZgIlluminateTelemetryErrorType`\n\nFollowing `MessagingTelemetryEventType.kt` and `MessagingTelemetryErrorType.kt` in the same telemetry directory. These are optional unless the team requires them for Datadog filtering."
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "wire-monitoring-bus",
|
|
103
|
+
"title": "Wire the MonitoringBus",
|
|
104
|
+
"runCondition": { "var": "needsClickstream", "equals": true },
|
|
105
|
+
"prompt": "Wire the MonitoringBus for this feature using Variant A.\n\nVariant A: each observer implements `EventObserver<[Feature]MonitoringEvent>` directly and is bound via `@Binds @IntoSet` in the feature's DI module. Do not introduce a Dagger marker interface unless cross-module observer contribution from another Gradle module is explicitly required.\n\n**Files to create:**\n\n`[Feature]MonitoringEvent.kt` — `sealed interface : MonitoringEvent`\n- One subtype per action in `actionsToTrack`\n- Events needing clickstream: `data class ... : [Feature]MonitoringEvent, AnalyticsCapable { override val analyticsModel = [Feature]AnalyticsEvents.X.analytics }`\n- Analytics-silent events: do not implement `AnalyticsCapable`\n\n`[Feature]MonitoringBus.kt` — `@Singleton`, holds a `Set<EventObserver<[Feature]MonitoringEvent>>`; delegates to `FeatureMonitoringBusImpl` (inject `FeatureMonitoringBusFactory`)\n\n`[Feature]MonitoringPublisher.kt` — interface `fun publish(event: [Feature]MonitoringEvent)` + `Real[Feature]MonitoringPublisher` with `@Singleton @ContributesBinding(AppScope::class)`\n\n`[Feature]AnalyticsObserver.kt` — `EventObserver<[Feature]MonitoringEvent>`: cast to `AnalyticsCapable?`, skip if null (correct for analytics-silent events), forward `analyticsModel` to `SimpleAnalyticsTracker`\n\n`[Feature]MonitoringDebugObserver.kt` — `EventObserver<[Feature]MonitoringEvent>`: exhaustive `when` on all event types, logging each one. Bound `@Binds @IntoSet` in the module.\n\n`[Feature]MonitoringModule.kt` — `@Module @ContributesTo(AppScope::class)`: `@Binds` the bus and publisher; `@Binds @IntoSet` each observer",
|
|
106
|
+
"promptFragments": [
|
|
107
|
+
{
|
|
108
|
+
"id": "has-existing-bus",
|
|
109
|
+
"when": { "var": "hasExistingMonitoringBus", "equals": true },
|
|
110
|
+
"text": "A MonitoringBus already exists for this feature. Add the new MonitoringEvent subtypes to the existing sealed interface and register any new observers with @Binds @IntoSet in the existing module. Do not create a second bus."
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "integrate-viewmodel",
|
|
116
|
+
"title": "Integrate Tracking into the ViewModel",
|
|
117
|
+
"prompt": "Integrate the tracking calls into the ViewModel.",
|
|
118
|
+
"promptFragments": [
|
|
119
|
+
{
|
|
120
|
+
"id": "clickstream-integration",
|
|
121
|
+
"when": { "var": "needsClickstream", "equals": true },
|
|
122
|
+
"text": "Inject `[Feature]MonitoringPublisher` via `@VMInject constructor` and call `publish()` for each tracked user action.\n\nPreferred: return a `[Feature]Action.TrackEvent([Feature]MonitoringEvent.X)` from `reduceActions()`. The imperative shell calls `monitoringPublisher.publish(action.event)`.\n\nIf the ViewModel does not use the reducer-action pattern, call `monitoringPublisher.publish()` in the relevant private handler function.\n\nFor one-time impressions, use `TriggerOnceImpressionHandler` from `libraries/illuminate/impression-tracker`.\n\nDo not call `publish()` from Use Cases, Repositories, or UI composables.\n\nCapture `usedReducerActionPattern`: true if you returned a TrackEvent action from reduceActions(); false if imperative."
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"id": "telemetry-integration",
|
|
126
|
+
"when": { "var": "needsTelemetry", "equals": true },
|
|
127
|
+
"text": "Also inject `ZgIlluminateTelemetryContract` into the ViewModel:\n```kotlin\n@VMInject constructor(\n ...,\n private val telemetryContract: ZgIlluminateTelemetryContract\n)\n```\nFor each signal in `telemetryEventsNeeded`:\n- milestone / info events: `telemetryContract.logEvent([Feature]Telemetry.Event.RenderCompleted)`\n- errors: `telemetryContract.logException([Feature]Telemetry.Error.LoadFailed(throwable))`\n- timed operations: `telemetryContract.transactionStart(\"[feature]_load\")` before / `.transactionStop(\"[feature]_load\", success = true)` after\n\nRepositories and Use Cases may also inject `ZgIlluminateTelemetryContract` directly for data-layer errors. Reference call sites: `InboxViewModel.kt` lines 183, 198, 224."
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"id": "write-tests",
|
|
133
|
+
"title": "Write Tests",
|
|
134
|
+
"prompt": "Write tests for all instrumented tracking.",
|
|
135
|
+
"promptFragments": [
|
|
136
|
+
{
|
|
137
|
+
"id": "clickstream-tests",
|
|
138
|
+
"when": { "var": "needsClickstream", "equals": true },
|
|
139
|
+
"text": "**Reducer test** (when `usedReducerActionPattern` is true):\n```kotlin\nval result = reducer.reduceActions(state, newState, [Feature]Event.UserTappedX)\nassertTrue(result.any { it is [Feature]Action.TrackEvent && it.event is [Feature]MonitoringEvent.UserTappedX })\n```\nNo coroutines or mocks needed.\n\n**ViewModel / integration test** using a fake publisher:\n- Create `Fake[Feature]MonitoringPublisher` with `val published = mutableListOf<[Feature]MonitoringEvent>()`\n- Call `onEvent()` for each tracked user action\n- Assert `fake.published` contains the correct event subtypes\n\nWrite one test per action in `actionsToTrack`."
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"id": "telemetry-tests",
|
|
143
|
+
"when": { "var": "needsTelemetry", "equals": true },
|
|
144
|
+
"text": "**Telemetry tests:** create a `Fake[Feature]TelemetryContract : ZgIlluminateTelemetryContract` that accumulates calls in mutable lists. Reference the existing `FakeTelemetryContract` at `features/messaging/impl/src/test/java/com/zillow/android/messaging/impl/fakes/FakeTelemetryContract.kt` — there is no shared library fake, each feature creates its own. Assert that `loggedEvents`, `loggedErrors`, or `startedTransactions` contain the expected entries for each signal in `telemetryEventsNeeded`."
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": "final-verification",
|
|
150
|
+
"type": "loop",
|
|
151
|
+
"title": "Final Verification",
|
|
152
|
+
"loop": {
|
|
153
|
+
"type": "while",
|
|
154
|
+
"conditionSource": {
|
|
155
|
+
"kind": "artifact_contract",
|
|
156
|
+
"contractRef": "wr.contracts.loop_control",
|
|
157
|
+
"loopId": "final_verification_loop"
|
|
158
|
+
},
|
|
159
|
+
"maxIterations": 2
|
|
160
|
+
},
|
|
161
|
+
"body": [
|
|
162
|
+
{
|
|
163
|
+
"id": "final-verify-core",
|
|
164
|
+
"title": "Run Final Verification",
|
|
165
|
+
"templateCall": {
|
|
166
|
+
"templateId": "wr.templates.routine.final-verification",
|
|
167
|
+
"args": {
|
|
168
|
+
"deliverableName": "final-verification-findings.md"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"requireConfirmation": false
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"id": "final-verify-synthesize",
|
|
175
|
+
"title": "Synthesize, Fix, and Re-Verify",
|
|
176
|
+
"prompt": "Read `final-verification-findings.md` and decide what actually needs fixing.\n\nUse `invariants` and `acceptanceCriteria` from the understand step as the verification anchors. The verifier checks all instrumented signals: event coverage, DI completeness, telemetry call sites, silent drop risks, and test quality.\n\nDon't rubber-stamp the findings. For any finding that changes final acceptance, classify it:\n- `Confirmed`: checked against code, tests/build, or direct workflow context\n- `Plausible`: interesting but not verified enough yet\n- `Rejected`: contradicted by fuller context or evidence\n\nFix what needs fixing. Re-run affected tests or build to prove fixes worked.\n\nCapture:\n- `integrationFindings`\n- `integrationPassed`\n- `regressionDetected`",
|
|
177
|
+
"assessmentRefs": [
|
|
178
|
+
"build-correctness-gate",
|
|
179
|
+
"invariant-preservation-gate",
|
|
180
|
+
"implementation-gaps-gate"
|
|
181
|
+
],
|
|
182
|
+
"assessmentConsequences": [
|
|
183
|
+
{
|
|
184
|
+
"when": { "anyEqualsLevel": "low" },
|
|
185
|
+
"effect": {
|
|
186
|
+
"kind": "require_followup",
|
|
187
|
+
"guidance": "Address whichever gate scored low: build_correctness — fix compilation errors or failing tests. invariant_preservation — one or more invariants from the understand step are violated; fix the implementation. implementation_gaps — the gap scan was not completed or found unaddressed gaps; resolve or defer them explicitly."
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
"requireConfirmation": false
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"id": "final-verify-decision",
|
|
195
|
+
"title": "Final Verification Loop Decision",
|
|
196
|
+
"prompt": "Decide whether verification needs another pass.\n\n- Issues found and fixed: keep going so fixes get re-verified.\n- Implementation clean or issues resolved: stop.\n- Limit reached: stop and record what remains.\n\nWhen stopping, include: event and telemetry coverage status, test results, DI completeness, and any accepted follow-ups.\n\nEmit the loop-control artifact (`decision` must be `continue` or `stop`):\n```json\n{\n \"artifacts\": [{\"kind\": \"wr.loop_control\", \"decision\": \"stop\"}]\n}\n```",
|
|
197
|
+
"requireConfirmation": true,
|
|
198
|
+
"outputContract": {
|
|
199
|
+
"contractRef": "wr.contracts.loop_control"
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mercury-ios.clickstream-implementation",
|
|
3
|
+
"name": "Mercury iOS: Implement Feature Tracking",
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"description": "Guides an engineer through implementing clickstream analytics and/or telemetry for a mercury-ios ZillowMap feature. Conditionally handles either or both: discovers clickstream events, defines IlluminateEvents cases and telemetry signal keys, wires tracking into the ViewModel, and writes tests.",
|
|
6
|
+
"validatedAgainstSpecVersion": 3,
|
|
7
|
+
"about": "## Mercury iOS: Implement Feature Tracking\n\nThis workflow handles clickstream analytics, operational telemetry, or both — using `runCondition` to skip steps that don't apply.\n\n### What it does\n\n1. Identifies which tracking types are needed (clickstream, telemetry, or both)\n2. Discovers the clickstream event spec from Glean or user input (clickstream only)\n3. Defines `IlluminateEvents+[Feature].swift` extension cases (clickstream only)\n4. Defines telemetry signal keys or TKMonitor types (telemetry only)\n5. Wires the `IlluminateAnalyticsTrackable` mixin and `ZIMContextualBlock` updates (clickstream only)\n6. Integrates tracking calls into the ViewModel\n7. Writes tests and runs a final verification barrier\n\n### Reference implementations\n\n- Clickstream: `Modules/Messaging/Sources/Messaging/Analytics/IlluminateEvents/ZIM/IlluminateEvents+ZIM.swift`\n- Telemetry: `Modules/IlluminateTelemetry/Sources/IlluminateTelemetry/TelemetryMonitorImpl.swift`\n\n### When to use it\n\nUse this workflow when adding any combination of clickstream events or telemetry instrumentation to a ZillowMap feature module.\n\n### What it produces\n\n**Clickstream:** `IlluminateEvents+[Feature].swift`, `IlluminateSemanticEventName.[Feature]`, optional `ZIMContextualBlock` updates, `IlluminateAnalyticsTrackable` conformance, `MockAnalyticsAgent` tests\n\n**Telemetry:** `[Feature]TelemetryKeys.swift` constants or `TKMonitor` conformance, `ZGMonitoring` injection, mock monitor tests",
|
|
8
|
+
"examples": [
|
|
9
|
+
"Add clickstream tracking to the new listing alert feature",
|
|
10
|
+
"Add telemetry error tracking and transaction timing to the connection flow",
|
|
11
|
+
"Instrument the buyer connection request flow with both analytics and telemetry",
|
|
12
|
+
"Wire telemetry transaction timing for the conversation load operation on iOS"
|
|
13
|
+
],
|
|
14
|
+
"recommendedPreferences": {
|
|
15
|
+
"recommendedAutonomy": "guided",
|
|
16
|
+
"recommendedRiskPolicy": "balanced"
|
|
17
|
+
},
|
|
18
|
+
"preconditions": [
|
|
19
|
+
"The feature module exists and the ViewModel is already implemented.",
|
|
20
|
+
"Agent has read access to the ZillowMap codebase.",
|
|
21
|
+
"Glean MCP is available for clickstream event spec discovery (falls back to user input if not found)."
|
|
22
|
+
],
|
|
23
|
+
"metaGuidance": [
|
|
24
|
+
"USE EXISTING PATTERN: extend IlluminateEvents with a nested feature enum. Each case has `var event: IlluminateEvent` with hardcoded integer ID and typed enum fields. Do not create new tracker protocols or classes.",
|
|
25
|
+
"TRACKABLE MIXIN: ViewModel conforms to IlluminateAnalyticsTrackable and calls trackEvent(_:using:and:) passing messagingRepo (IlluminateAnalyticsTracker) and clickstreamTracker (IlluminateEventsManager).",
|
|
26
|
+
"CONTEXT ENRICHMENT: ZIMContextualBlock in MessagingRepositoryImpl enriches every event. Add new fields with an immutable updateWith*() method. Never reach into the contextual block from the ViewModel directly.",
|
|
27
|
+
"NO USE CASE PATH: do not use TrackAnalyticsEventUseCase or MessagingAnalyticsRepositoryImpl.getAnalyticsContext() — the context impl returns an empty stub and silently delivers empty analytics context.",
|
|
28
|
+
"KILL SWITCH: zillow_ios_zim_analytics_refactor is currently disabled. Always use trackEvent(_:using:and:) with both parameters. Do not adopt the single-parameter path until the kill switch is enabled.",
|
|
29
|
+
"TEST WITH MockAnalyticsAgent (already in MessagingMocks): it records trackedEvents:[IlluminateEvent]. Assert on exact event equality. Use .fixture() extension methods for test data.",
|
|
30
|
+
"EVENT IDS: integer event IDs cannot be inferred from code. They must come from the Glean event spec or user input. Hardcode them directly inside the IlluminateEvent init in each case.",
|
|
31
|
+
"TELEMETRY: use TKMonitorProviding with a feature-specific DI key. Define typed EventType/ErrorType/TransactionType enums. Call monitor?.send(event:)/send(error:)/begin(transaction:)/end(transaction:). Reference: CallScheduler pattern."
|
|
32
|
+
],
|
|
33
|
+
"assessments": [
|
|
34
|
+
{
|
|
35
|
+
"id": "build-correctness-gate",
|
|
36
|
+
"purpose": "The implementation compiles and all tests pass.",
|
|
37
|
+
"dimensions": [
|
|
38
|
+
{
|
|
39
|
+
"id": "build_correctness",
|
|
40
|
+
"purpose": "Build succeeds and tests pass. No compilation errors or failing assertions.",
|
|
41
|
+
"levels": ["low", "high"]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "invariant-preservation-gate",
|
|
47
|
+
"purpose": "Invariants captured in the understand step still hold in the implemented code.",
|
|
48
|
+
"dimensions": [
|
|
49
|
+
{
|
|
50
|
+
"id": "invariant_preservation",
|
|
51
|
+
"purpose": "Each named invariant has been verified in the implementation.",
|
|
52
|
+
"levels": ["low", "high"]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "implementation-gaps-gate",
|
|
58
|
+
"purpose": "A deliberate scan for gaps surfaced during implementation has been completed.",
|
|
59
|
+
"dimensions": [
|
|
60
|
+
{
|
|
61
|
+
"id": "implementation_gaps",
|
|
62
|
+
"purpose": "Active scan completed: gaps are fixed inline, filed as follow-up tickets, or explicitly deferred.",
|
|
63
|
+
"levels": ["low", "high"]
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"steps": [
|
|
69
|
+
{
|
|
70
|
+
"id": "understand-feature",
|
|
71
|
+
"title": "Understand the Feature",
|
|
72
|
+
"prompt": "Read the feature module you are adding tracking to.\n\nFind:\n- The ViewModel: does it already conform to `IlluminateAnalyticsTrackable`? Does it already inject `messagingRepo` and `clickstreamTracker` via `@LazyInjected`?\n- Any existing `IlluminateEvents+[Feature].swift` file in the feature module\n- Existing `trackEvent` or `IlluminateEvents` references in the module\n\nAlso read the canonical clickstream reference now:\n`Modules/Messaging/Sources/Messaging/Analytics/IlluminateEvents/ZIM/IlluminateEvents+ZIM.swift`\n\nIdentify which user actions (taps, page loads, impressions) should generate clickstream events. Also identify whether any operations need operational telemetry: error paths worth tracking in Datadog, performance-critical operations worth timing as transactions, or key milestones worth logging.\n\nNote: clickstream is for product analytics (user behavior); telemetry is for operational health (errors, performance, Datadog).\n\nCapture:\n- `hasExistingEventsExtension`: true if an `IlluminateEvents+[Feature].swift` already exists\n- `hasTrackableMixin`: true if the ViewModel already conforms to `IlluminateAnalyticsTrackable`\n- `featureModulePath`: path to the feature's Swift module source\n- `actionsToTrack`: list of action names needing clickstream events (e.g. [\"userOpenedScreen\", \"userTappedSend\"])\n- `invariants`: correctness rules that must hold (e.g. [\"Every actionsToTrack action has one IlluminateEvents case\", \"All IlluminateEvent fields use typed enum values\", \"trackEvent called with both messagingRepo and clickstreamTracker\"])\n- `acceptanceCriteria`: what done looks like (e.g. [\"All events in events[] fire when user acts\", \"MockAnalyticsAgent records exact IlluminateEvent equality for each action\"])\n- `needsClickstream`: true if product analytics events are needed\n- `needsTelemetry`: true if operational telemetry is needed (errors, timings, transactions)\n- `telemetryEventsNeeded`: list of telemetry signals (e.g. [\"renderDuration transaction\", \"loadError error\", \"submitSuccess event\"])"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "discover-events",
|
|
76
|
+
"title": "Discover Clickstream Event Definitions",
|
|
77
|
+
"runCondition": { "var": "needsClickstream", "equals": true },
|
|
78
|
+
"prompt": "Find the analytics event spec for this feature.\n\nSearch Glean for event definitions. Try these queries in order until you find something useful:\n1. The ticket number (ACEI/ICEI) — check the session goal or `git log` for a reference\n2. \"[feature name] clickstream events\"\n3. \"[feature name] analytics event type\"\n4. \"[feature name] tracking spec\"\n\nA useful spec defines per event:\n- Event type ID (an integer, e.g. 5526)\n- Semantic event name string (e.g. \"sendMessageComplete\")\n- Template ID (e.g. 337)\n- Trigger type: interaction / pageView / impression\n- Source (`MessagingSources` enum value)\n- Trigger object (`MessagingTriggerObject` enum value, optional)\n- Trigger location (`MessagingLocation` enum value)\n\nIf Glean returns a document with these values, extract them for each action in `actionsToTrack`.\n\nIf no spec is found in Glean, tell the user:\n\n\"I could not find an analytics event spec for this feature in Glean. For each of the following actions [list actionsToTrack], please provide: (1) integer event ID, (2) semantic event name string, (3) template ID, (4) trigger type (interaction/pageView/impression), (5) source, (6) trigger object (optional), (7) trigger location.\"\n\nCapture:\n- `events`: array of {name, eventId, semanticEventName, templateId, triggerType, source, triggerObject, triggerLocation}\n- `eventsSource`: \"glean\" or \"user_provided\"",
|
|
79
|
+
"requireConfirmation": true
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "define-events",
|
|
83
|
+
"title": "Define IlluminateEvents Extension",
|
|
84
|
+
"runCondition": { "var": "needsClickstream", "equals": true },
|
|
85
|
+
"prompt": "Write the `IlluminateEvents+[Feature].swift` extension for this feature.\n\nFor each entry in `events`, write a corresponding case. Follow the pattern in `IlluminateEvents+ZIM.swift` exactly:\n\n```swift\nextension IlluminateEvents {\n enum [Feature]: CaseIterable {\n case userOpenedScreen\n case userTappedSend\n // ...\n\n var event: IlluminateEvent {\n switch self {\n case .userOpenedScreen:\n return IlluminateEvent(\n id: <eventId>,\n semanticEventName: IlluminateSemanticEventName.[Feature].openedScreen,\n templateId: <templateId>, templateVersionId: 1, versionId: 1,\n triggerType: .pageView,\n source: .<MessagingSources case>,\n triggerObject: .<MessagingTriggerObject case>,\n triggerLocation: .<MessagingLocation case>\n )\n }\n }\n }\n}\n```\n\nAlso extend `IlluminateSemanticEventName` with a nested enum for the feature's semantic name strings:\n\n```swift\nextension IlluminateSemanticEventName {\n enum [Feature] {\n static let openedScreen = \"[feature_opened_screen]\"\n // ...\n }\n}\n```\n\nNever use raw integer literals outside the `IlluminateEvent` init. No separate constants files needed.",
|
|
86
|
+
"promptFragments": [
|
|
87
|
+
{
|
|
88
|
+
"id": "has-existing-extension",
|
|
89
|
+
"when": { "var": "hasExistingEventsExtension", "equals": true },
|
|
90
|
+
"text": "An IlluminateEvents extension already exists for this feature. Add the new cases to the existing enum rather than creating a new file. Match the naming style already in use."
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "define-telemetry-events",
|
|
96
|
+
"title": "Define Telemetry Signal Keys",
|
|
97
|
+
"runCondition": { "var": "needsTelemetry", "equals": true },
|
|
98
|
+
"prompt": "Define the telemetry types for this feature using the `TKMonitorProviding` pattern.\n\nThe canonical pattern in ZillowMap uses `TKMonitorProviding` with a feature-specific DI key. Reference: `Modules/Touring/Sources/TourScheduling/AnalyticMonitoring/SessionMonitor.swift`.\n\n**Step 1 — Define the monitor provider** in a new `[Feature]Monitor.swift`:\n\n```swift\nstruct [Feature]Monitor: TKMonitorProviding {}\n\nextension [Feature]Monitor {\n enum EventType: TKMonitorEvent {\n case renderCompleted\n case submitSucceeded\n // one case per event-type signal in telemetryEventsNeeded\n var name: String { switch self { case .renderCompleted: return \"[feature]_render_completed\"; ... } }\n var action: TKMonitorAction { .custom }\n var attributes: [String: Encodable] { [:] }\n }\n enum ErrorType: TKMonitorErrors {\n case loadFailed(Error)\n // one case per error-type signal\n var errors: [TKMonitorError] { switch self { case .loadFailed(let e): return [TKMonitorError(error: e, attributes: [:])] } }\n }\n enum TransactionType: TKMonitorTransaction {\n case loadOperation(TKTransactionType)\n var id: String { \"[feature]_load_operation\" }\n var attributes: [String: Encodable] { [:] }\n var action: TKMonitorAction { .custom }\n var type: TKTransactionType { switch self { case .loadOperation(let t): return t } }\n }\n}\n```\n\nOnly add `ErrorType` if `telemetryEventsNeeded` includes error signals. Only add `TransactionType` if there are transaction signals.\n\n**Step 2 — Register in DI** (add to the feature's `Container` extension):\n\n```swift\nprotocol [Feature]MonitorSupporting: TKMonitorTracking, TKMonitorSupporting\n where MonitorProvider == [Feature]Monitor {}\nextension TKMonitor<[Feature]Monitor>: [Feature]MonitorSupporting {}\n\nextension Container {\n static let [feature]Monitor = DIFactory<(any [Feature]MonitorSupporting)?>(scope: .cached) { nil }\n}\n```\n\nRegister the real implementation at app startup or in the feature's DI setup: `Container.[feature]Monitor.register { TKMonitor<[Feature]Monitor>(...) }`.\n\nCapture:\n- `telemetryDIKey`: the Container key name (e.g. \"[feature]Monitor\")"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "wire-tracking",
|
|
102
|
+
"title": "Wire Tracking into the ViewModel",
|
|
103
|
+
"runCondition": { "var": "needsClickstream", "equals": true },
|
|
104
|
+
"prompt": "Wire clickstream tracking into the ViewModel. Two checks first.\n\n**1. Context check:** Do any events in `events` need data not currently in `ZIMContextualBlock` (a new listing ID, a custom count, etc.)?\n\nIf yes — add the field and update method:\n- Add a `let` property with a default value to `ZIMContextualBlock`\n- Add an immutable `updateWith[FieldName](_ value: Type) -> ZIMContextualBlock` method following the existing pattern in `IlluminateEventsContextualBlock.swift`\n- Call it from `MessagingRepositoryImpl` at the point where the data becomes available\n\nIf no — proceed directly to step 2.\n\n**2. ViewModel wiring:**\n\nConform to `IlluminateAnalyticsTrackable` and inject dependencies:\n\n```swift\nclass [Feature]ViewModel: ObservableObject, IlluminateAnalyticsTrackable {\n @LazyInjected(Container.Messaging.messagingRepo) var messagingRepo\n @LazyInjected(Container.IlluminateAnalytics.analytics) var clickstreamTracker\n\n func onUserTappedSend() {\n trackEvent(IlluminateEvents.[Feature].userTappedSend.event,\n using: messagingRepo,\n and: clickstreamTracker)\n }\n}\n```\n\nFor page view events, call from a ViewModel lifecycle method invoked by the view's `.onAppear`.\n\nCapture:\n- `addedContextualFields`: true if new `ZIMContextualBlock` fields were added; false otherwise",
|
|
105
|
+
"promptFragments": [
|
|
106
|
+
{
|
|
107
|
+
"id": "has-mixin",
|
|
108
|
+
"when": { "var": "hasTrackableMixin", "equals": true },
|
|
109
|
+
"text": "The ViewModel already conforms to IlluminateAnalyticsTrackable. Skip the conformance declaration and only add the new trackEvent() call sites."
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"id": "integrate-viewmodel",
|
|
115
|
+
"title": "Integrate Telemetry into the ViewModel",
|
|
116
|
+
"runCondition": { "var": "needsTelemetry", "equals": true },
|
|
117
|
+
"prompt": "Inject the feature telemetry monitor into the ViewModel and wire it up for each signal in `telemetryEventsNeeded`.\n\nInject via `@LazyInjected` using the feature-specific DI key defined in `define-telemetry-events`:\n\n```swift\n@LazyInjected(Container.[feature]Monitor)\nprivate var monitor: (any [Feature]MonitorSupporting)?\n```\n\nFor each signal:\n- events: `monitor?.send(event: [Feature]Monitor.EventType.renderCompleted)`\n- errors: `monitor?.send(error: [Feature]Monitor.ErrorType.loadFailed(error))`\n- transaction start: `monitor?.begin(transaction: [Feature]Monitor.TransactionType.loadOperation(.begin))`\n- transaction end (success): `monitor?.end(transaction: [Feature]Monitor.TransactionType.loadOperation(.success))`\n- transaction end (failure): `monitor?.end(transaction: [Feature]Monitor.TransactionType.loadOperation(.failure))`\n\nReference call sites: `Modules/CallScheduler/Sources/CallScheduler/CallSchedulerFlowView.ViewModel.swift` lines 109, 169, 232-243."
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "write-tests",
|
|
121
|
+
"title": "Write Tests",
|
|
122
|
+
"prompt": "Write tests for all instrumented tracking.",
|
|
123
|
+
"promptFragments": [
|
|
124
|
+
{
|
|
125
|
+
"id": "clickstream-tests",
|
|
126
|
+
"when": { "var": "needsClickstream", "equals": true },
|
|
127
|
+
"text": "`MockAnalyticsAgent` is already in `MessagingMocks` — use it directly:\n\n```swift\nfunc testUserTappedSendFiresEvent() {\n let mockAgent = MockAnalyticsAgent()\n withTestContainer { Container.someAnalyticsAgent.register { mockAgent } }\n sut.onUserTappedSend()\n XCTAssertEqual(mockAgent.trackedEvents.count, 1)\n XCTAssertEqual(mockAgent.trackedEvents.first,\n IlluminateEvents.[Feature].userTappedSend.event)\n}\n```\n\n`IlluminateEvent` conforms to `Equatable` — assert on exact event equality. Use `.fixture()` extension methods for test data. Write one test per action in `actionsToTrack`."
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"id": "telemetry-tests",
|
|
131
|
+
"when": { "var": "needsTelemetry", "equals": true },
|
|
132
|
+
"text": "Telemetry tests: use `MockMonitor` from `Modules/IlluminateTelemetry/Sources/IlluminateTelemetryMocks/MockMonitor.swift` — it implements `ZGMonitoring` and records calls via closures (`didAddEvent`, `didBeginTransaction`, `didEndTransaction`, `didAddError`). Register it in the test container: `Container.monitor.register { mockMonitor }`. Alternatively, use `MockZGMonitoring` from `Modules/HomeLoansMonitoring/Tests/HomeLoansMonitoringTests/Mocks/MockZGMonitoring.swift` which accumulates calls in arrays for easier assertion. For `TKMonitor`-level testing, assert on the typed `EventType`/`ErrorType` values rather than the underlying `ZGMonitoring` calls."
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": "final-verification",
|
|
138
|
+
"type": "loop",
|
|
139
|
+
"title": "Final Verification",
|
|
140
|
+
"loop": {
|
|
141
|
+
"type": "while",
|
|
142
|
+
"conditionSource": {
|
|
143
|
+
"kind": "artifact_contract",
|
|
144
|
+
"contractRef": "wr.contracts.loop_control",
|
|
145
|
+
"loopId": "final_verification_loop"
|
|
146
|
+
},
|
|
147
|
+
"maxIterations": 2
|
|
148
|
+
},
|
|
149
|
+
"body": [
|
|
150
|
+
{
|
|
151
|
+
"id": "final-verify-core",
|
|
152
|
+
"title": "Run Final Verification",
|
|
153
|
+
"templateCall": {
|
|
154
|
+
"templateId": "wr.templates.routine.final-verification",
|
|
155
|
+
"args": {
|
|
156
|
+
"deliverableName": "final-verification-findings.md"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"requireConfirmation": false
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": "final-verify-synthesize",
|
|
163
|
+
"title": "Synthesize, Fix, and Re-Verify",
|
|
164
|
+
"prompt": "Read `final-verification-findings.md` and decide what actually needs fixing.\n\nUse `invariants` and `acceptanceCriteria` from the understand step as the verification anchors. The verifier checks all instrumented signals: event coverage, kill switch compliance, contextual block completeness, telemetry call sites, and test quality.\n\nDon't rubber-stamp the findings. For any finding that changes final acceptance, classify it:\n- `Confirmed`: checked against code, tests/build, or direct workflow context\n- `Plausible`: interesting but not verified enough yet\n- `Rejected`: contradicted by fuller context or evidence\n\nFix what needs fixing. Re-run affected tests or build to prove fixes worked.\n\nCapture:\n- `integrationFindings`\n- `integrationPassed`\n- `regressionDetected`",
|
|
165
|
+
"assessmentRefs": [
|
|
166
|
+
"build-correctness-gate",
|
|
167
|
+
"invariant-preservation-gate",
|
|
168
|
+
"implementation-gaps-gate"
|
|
169
|
+
],
|
|
170
|
+
"assessmentConsequences": [
|
|
171
|
+
{
|
|
172
|
+
"when": { "anyEqualsLevel": "low" },
|
|
173
|
+
"effect": {
|
|
174
|
+
"kind": "require_followup",
|
|
175
|
+
"guidance": "Address whichever gate scored low: build_correctness — fix compilation errors or failing tests. invariant_preservation — one or more invariants from the understand step are violated; fix the implementation. implementation_gaps — the gap scan was not completed or found unaddressed gaps; resolve or defer them explicitly."
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
"requireConfirmation": false
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"id": "final-verify-decision",
|
|
183
|
+
"title": "Final Verification Loop Decision",
|
|
184
|
+
"prompt": "Decide whether verification needs another pass.\n\n- Issues found and fixed: keep going so fixes get re-verified.\n- Implementation clean or issues resolved: stop.\n- Limit reached: stop and record what remains.\n\nWhen stopping, include: event and telemetry coverage status, test results, kill switch compliance, and any accepted follow-ups.\n\nEmit the loop-control artifact (`decision` must be `continue` or `stop`):\n```json\n{\n \"artifacts\": [{\"kind\": \"wr.loop_control\", \"decision\": \"stop\"}]\n}\n```",
|
|
185
|
+
"requireConfirmation": true,
|
|
186
|
+
"outputContract": {
|
|
187
|
+
"contractRef": "wr.contracts.loop_control"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
}
|