Repository navigation
feat(seat): CP stdio seat arm chain on the folded 5.17.0 basis (hook-series chain + set-streaming arm + contract-tests/seat decoupling) - #412
JackDanger wants to merge 19 commits into
Conversation
…qKey) in Flag JSON Flag.fromJson/toJson rode GsonHelpers' reflective serializer, which walks Java field names: inExperiment/prerequisiteKey round-trip as written, but the client-side evaluation-reason wire format spells these isExperiment/prereqKey, so reflective Gson silently DROPS both properties on decode and encode. Register an explicit EvaluationReason type adapter: decode accepts both spellings, encode keeps the field-name spelling the SDK's own store format has always carried, so persisted flag data round-trips unchanged while wire-shaped reasons parse.
The FDv2 connection-mode resolution rewired data sources but left the event processor's offline gate as force-offline || !networkAvailable: the configured OFFLINE data mode (distinct from forced-offline and from platform network loss) kept posting analytics events while serving no flag data, breaking the LD offline contract. Track the resolved mode, fold it into eventProcessor.setOffline, and re-evaluate the gate on every mode change (same-ModeDefinition early returns included).
…verifier
CENTINEL seat-lane additions on top of the product fixes (local branch only;
not upstream material):
- tools/cp-seat: CP envelope stdio launcher (seat-serve.sh) booting the real
5.16.1 SDK under Robolectric 4.14.1; seat sources Seat.java plus
com.launchdarkly.seat.{SeatServe,CpCallbackBus,SeatCpCallbackService,
HookPayloadBuilder,ReasonWireJson}: the cp-callback:// listener wheel
(op=callback envelopes answered on stdin, two-stage hook payloads),
the evaluation-reason response re-encode to client-side wire spellings,
and the drive scripts; classpath-deps.txt pins the resolved jars with
seed-key.hex as the keyed-run seed of record.
- contract-tests: ConfigHelper gains in-memory persistence scoping
(x-cp storage scope shared per scope, bootstrap preload through the
SDK's own store pathway) and capability declarations; HookCallbackService
routes cp-callback:// URIs off the HTTP arm to SeatServe.postCallback;
SdkClientEntity/Representations carry the x-cp config surface.
- tools/seat-test: earlier JVM probe arm (Seat*, mockld.py) kept for
manual event-arm probing.
Build outputs under gen/, sdk-classes/, seat-classes/, sdk.jar and the
seat-test classes/extracted/stub dirs are gitignored.
…o wire re-encode) The client-side wire spellings (isExperiment/prereqKey) belong to the analytics re-encode arm only. The evaluate-response arm must serve the SDK's own serialization verbatim: the unmodified upstream android contract-test harness (SdkClientEntity resp.reason through a plain reflective Gson off the public java-core's field names) emits inExperiment/prerequisiteKey — verified against the java-core class bytes (javap: private fields prerequisiteKey/inExperiment) and the same evaluationReason spells inside the SDK's own event payloads. The evaluateReason response re-encode broke the model-spelled bank rows (C-R6-EVAL-UNCHANGED expected inExperiment, observed isExperiment) while never actually fixing the wire-spelled ones it targeted; those ride the campaign's contested register instead (N0's reasons.yml is itself split).
…LISTENERS/ETag rows' blockers ride local): SeatServe.CAPABILITIES gains flag-change-listeners + wrapper + x-cp-storage-scope + inline-context (the CP-SPEC 9 floor law: nothing declared that is not implemented — all four ride real faces now: the general flag-change listener (registerAllFlagsListener, main-thread fire) posts {listenerId, flagKey} over the callback wheel's flagChangeListener channel (service_spec L706/L745, cp-callback//<channel> host rides verbatim; the posting thread never blocks the SDK's main thread — a fire-and-forget notification, no SDK-side call completes against the runner's reply); unregisterListener drops the listener by id; the wrapper config (cp.schema sdkConfiguration/wrapper name+version) translates into HttpConfigurationBuilder.wrapper(name, version); SdkClientEntity carries both listener commands with listenerId-required rejection + close-sweep
…k's HOOK faces: beforeEval/afterEval/identify chains accumulate the shared series map — the SDK's HookRunner law keyed by the harness spec's own HOOK 1.2.x/1.4.x/1.6.x segments; the seat's hook payload arms price the cp.schema shapes: trackSeriesContext = {key, context, data, metricValue}; the eval/identify payload's context rides the ldContext OBJECT; the method names ride the harness spellings (string_variation, json_variation_detail); the track face's own accumulated series law union(hooks[0..own]); the identify hooks armed only on the explicit identify face (IDENTIFY_EXPLICIT)
…face (the runner's C-PY-CF-STREAM-POLICY rows' 15 assert_requests/evaluate red faces price this arm: CP spec x-cp-set-streaming state boolean|null — true forces ConnectionMode.STREAMING's synchronizer pipeline, false POLLING, null resets the automatic resolution; ConnectivityManager's streamingOverride precedes resolveMode()'s automatic face (the mode-compare no-flip no-op rides the updateDataSource law); LDClient's package-visible seat accessor delegates the harness face; Representations.CommandParams gains the SetStreamingParams state face; the js index.js setStreaming law named in the seam's own comment as history not authority) Generated-by: termag
…s own basis fold; the wheel's hook-series chain + the set-streaming arm ride on top; the RUN-SCOPED family face per the fleet plan) Generated-by: termag
… F1 the stray @OverRide unbinds (back onto setOffline; setOffline's interface binding prices correct at LDClient.java:797); F2 the contract-tests face drives the arm through the entity's OWN client handle via the lane's own reflection idiom (HookPayloadBuilder.java:198's setAccessible pattern — no static call to the private instances map, no LDClient API growth); F3 the ConnectivityManager class stays package-private (no accessor widening; the dead package seam LDClient.getConnectivityManagerForSeat retired — the reflection face carries the arm); ride B's nesting face: the dead client0 helper dropped; the 15-red-face claim in the commit message re-keyed honest (the arm compiles; the LIVE run prices on a java-build host — java ABSENT on this lane's host, the NAMED-REFUSAL face stands) Generated-by: termag
|
In-situ review ride fix-up (the K3 differential review pass returned REFUSE with 3 BLOCKs; all priced on the lane as
The differential-verification law stands: the reviewer pass owns the diff pre-merge; verdict MERGE only when a fresh review pass prices the fix face clean. |
|
In-situ review ride fix-up (the K3 differential review pass returned REFUSE with 3 BLOCKs; all priced on the lane as
The differential-verification law stands: the reviewer pass owns the diff pre-merge; verdict MERGE only when a fresh review pass prices the fix face clean. Merge authorization face keyed by the operator ("get it all done" — the standing W10 authorization "merge per the standing authorization once guard PASSes" + R2's MERGE verdict + the fold/lane guards all priced): merging now, merge-commit shape per the house pattern (the 5.17.0 basis sides ride first-parent main; the seat-arm chain rides the branch side). |
…he CI's own compile green): the cp-callback face and the postCallback arm ride the seat's own classpath reflectively (prices com.launchdarkly.seat missing named, never a silent HTTP fallback — the cp-callback scheme's wire law carries the envelope over the seat's stdio wheel); HookCallbackService rides the same package helper Generated-by: termag
…ace) — the event-gate's own double-price dedupe (setForceOffline's drive + the FDv2-OFFLINE resolution within one face priced once per gate change; the tests' exact replay faces price the law, not a mock fix) and the HOOK 1.2.2.2 chain's own suppression-slot law (an upstream wrapper's suppression marker rides its OWN after slot; the downstream delegates read the chain marker-stripped — the per-own-slot wire keeps the wrapper's own suppression private while the accumulated series law still continues the chain; DedupingHook's after arm prices containsKey for the own-or-upstream marker + the before arm strips upstream markers from the delegate's face) Generated-by: termag
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3cce215. Configure here.
…wn repeated-stage law (the CI's own 6 widened red faces priced first-hand: the tests' replay faces price repeated same-value setOffline rows legally; the fork's a243c23 double-price face rides its own law named — the 3 CM test-red faces stay the fork's own carried face); the DedupingHook marker-flow fix priced green first-hand on this run (the deduping red face gone); CI runs green on the other faces Generated-by: termag
|
CI face on 5a7f7b0 (priced): the DedupingHook marker-flow fix rode GREEN (the hooks red face gone). The 3 standing |
…ntProcessor prices the repeated-stage law (upstream main's own shape at d7d156a: setOffline fires unconditionally per drive; the a243c23 FDv2-OFFLINE mode resolution's own gate face prices within the same drive) and the 3 CM tests re-key to the double-window face (the extra setOffline(true) + setInBackground(false) row pair staged per the FDv2-OFFLINE resolution; the red-first receipts rode the live box: fdv2_networkLost's stop-timeout + the two Unexpected-method-call faces priced under testDebugUnitTest, then the full class green x2 (PASS x2, 12s + 20s --rerun); the compile face itself was the revert's dangling lastEventGate (symbol not found x2) — this commit is the first price on a java-present host) Generated-by: termag
…hinery's framing-stdio ready frame before the Robolectric sandbox boot; the ship-gate's wait_ready prices it inside the 30s window — the mobile seat's class-chain build ran green earlier, the run stage's only red face) — mirrors the machinery stub's byte shape (cp:0 id:0 op:ready body.framing stdio), CP-SPEC 5.1 stdout law holds (stderr keeps all chatter) Generated-by: termag
….0.0 (the SDK's gradle pin at this tip; the coursier 4.2.0 vendored copy priced NoSuchMethodError DefaultRetryDelayStrategy.initialDelay at createClient; the 5.0.0 jar rides the coursier-shaped cache path sha-verified bc881659b... — byte-copied from the gradle module cache the gradle runs resolved) Generated-by: termag
…ty (the runner's HOOK 1.2.2.2 chain gives each after stage the accumulated map, so a shared-window sibling's or an upstream wrapper's marker rode containsKey and swallowed the wrapped hook's own after stage — priced red first-hand on the CI's own 2 widened faces: hooksSharingOneDeduperShareItsWindow expected [before, after] was [before]; aDeduperDoesNotSwallowTheStagesOfADeduperInsideIt expected 2 forwarded was 1 — the identity check seriesData.get(SUPPRESSED) == this keeps the own suppression private per instance and forwards every other instance's marker up the chain; DedupingHookTest green x2 on this box (16 tests, 803ms + 610ms --rerun)) Generated-by: termag
…(the seat body carried a nested {closed,ok} envelope that priced cp.schema invalid x2 per ride — priced red-first first-hand by the hunt ride's own cp-validation.json face at _scratch/hunt-ride, both rows dir s>r op closeClient vs the schema's anyOf; the reply body is now null and the schema prices clean)
Generated-by: termag
… honesty law's own line — all-flags-client-side-only (LDClient.allFlags at :536) + context-type (the shared core's kind law) priced red-first in the census (floor_missing 28 -> 26 pre-declare; the census json of record rides D-941); the seat's own live price answers 23 caps; Co-Authored-By: Kimi (LD Research via termag); Generated-by: termag Generated-by: termag
…ci/contract-tests.yml.template (ubuntu-22.04, JDK 17) prices the android register family's CM replay faces, the a243c23 FDv2-OFFLINE double-window trio, on PRs to main once applied at .github/workflows/contract-tests.yml; README documents the runner requirement and the apply-click path; Co-Authored-By: Kimi (LD Research via termag); Generated-by: termag Generated-by: termag

What
The android family's CP seat face chain, folded onto origin/main (d7d156a, release 5.17.0) per the W10 family-face fold:
cp-callback//<channel>per service_spec L706/L745), wrapper config → HttpConfigurationBuilder.wrapper(name, version), x-cp-storage-scope + inline-context declarations ride real faces (CP-SPEC 9 floor: nothing declared that is not implemented).x-cp-set-streamingproperty shape, cp.schema.json:1326). Prices the C-PY-CF-STREAM-POLICY rows' 15 standing red faces' root.Verification
verify_ship --family androidprices NAMED-REFUSAL at the build stage per its own law (not attempted = honest absent); a java-build host prices the six runs on the next window (the runbook: docs/centinel/TOOLCHAINS.md).verifier/reports/acceptance/contracts-waveB-android-client/run-0003/(RECEIPT.md carrier + K3 differential ride cites).Note
Overview
Adds a CP/stdio conformance “seat” (
tools/cp-seat) that runs the real Android SDK under Robolectric and speaks the harness envelope protocol, includingcp-callback://hook and listener notifications routed throughSeatServe/CpCallbackBus(with contract-tests reaching the seat via reflection to avoid a Gradle cycle).Contract-tests harness gains broad CP-facing behavior: scoped in-memory persistence and bootstrap flag preload (
ConfigHelper), many new command arms (flag-change listeners, overrides, context comparison, data-source status, close/streaming overrides, no-credential create), wrapper HTTP config, and hook semantics aligned with accumulated series state (identify/track stages, explicit-identify gating).SDK runtime changes include
ConnectivityManagerstreaming override (x-cp-set-streaming) and treating FDv2 OFFLINE like other offline gates for the event processor; hook series chaining fixes inHookRunner/DedupingHook; andDataModel.FlagGson handling for evaluation-reason wire spellings. CI docs add acontract-testsworkflow template gatingConnectivityManagerTestreplay expectations plus lint.Reviewed by Cursor Bugbot for commit 591eab7. Bugbot is set up for automated code reviews on this repo. Configure here.