Repository navigation
Fabric switch: actuation log, 16 modeling gaps, and the convergence build plan - #11524
Conversation
…uild plan Documents the switch-side investigation and defines the modeled path to converge the CRS812 fabric lanes to 100GBASE-CR2 when the correctly-coded QSFP-DD end arrives. No code yet; this is the design that the credential / read / converge PRs implement, plus the honest record of the manual actuation those PRs dissolve. - fabric-switch-actuation-log.md: the out-of-band actuation done under operator approval (find + read the switch, force-100G experiments on srv5, restore), the reviewer correction that MikroTik requires forced/autoneg-off (my "non-compliant" framing was wrong), the credential/restore incident, and the verdict at witnessed confidence: the QSFP56 host recode succeeded (byte 192 0x0B->0x40, NIC Supported Cable Speed 50G_2X->100G_2X) but no bilateral 100G link trains against the still-Generic QSFP-DD end, under either autoneg or forced paths, across all switch FEC modes. Switch-side coding is the leading hypothesis, NOT proven; the isolating test is a substitution control. - fabric-switch-100g-convergence-gap-analysis.md §6: 16 modeling gaps found while driving the hardware (G1 no autoneg axis, G2 FEC enum cannot express RS(544,514) that 100GBASE-CR2 needs, G3/G4 live/two-ended link outcome unmodeled, G6 no REST reader/apply, G7 no switch credential standing, G9 mstlink unmodeled, G10 ethtool cannot pin CR2, G12 fabric_switch_observed stale post-recode, G13 dispatch cannot fan out, G16 actuation ran on ad-hoc curl -- the scaffold to kill). - fabric-switch-convergence-build-plan.md: the normal path, layered per DESIGN §3 (extdeps interface / REST-transport realization / workflow policy), the credential mirroring spark bootstrap, and the PR sequence: read path first (safe, groundable now), converge apply deferred until the hardware links at 100G because its FEC/autoneg specifics are currently inferred not witnessed (§4d). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- FEC meaning fork (§3) + over-promotion (§4d): the actuation log called fec91 "correct for 100GBASE-CR2" and mapped the 100G intent to Fec91, contradicting this PR's own G2 (fec91 = RS(528,514); 100GBASE-CR2 needs RS(544,514)/KP4). That was a 50G observation promoted into a 100G requirement. Corrected in place with a CORRECTION note, the same treatment the autoneg "non-compliant" claim already had: fec91 is the FEC running at 50G, NOT the established 100G intent, and converge must not assume it (G2 obligates refusal if the switch cannot offer the mode's codeword). - Standing-observation fork (§3): §0 said the EEPROM was not re-read and establishing the coding was the "first work item", while G12 states byte 192 = 0x40 and NIC 100G_2X. Amended §0 with a SUPERSEDED note pointing at G12 as the one current roster: the bytes were read, the re-flash took, the host-coding question is closed, the live blocker is the switch-side QSFP-DD end. - PR-3/PR-4 dependency: PR-3's success criterion named "host mstlink", which is PR-4's deliverable. Reworded: the host negotiated-speed READ is unprivileged (ethtool, no grant), so PR-3's observe-both-ends criterion does not depend on PR-4; only FORCING the host does. PR-3 alone converges the switch and reports the host still at 50G rather than claiming success off the switch's local link-ok; PR-3 + PR-4 together achieve 100G. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
All three findings in review 67282 verified and fixed in the latest commit. 1. FEC meaning fork + §4d over-promotion — confirmed, corrected. The actuation log did call 2. Standing-observation fork — confirmed, superseded. §0 said the EEPROM was not re-read and establishing the coding was the "first work item"; G12 says byte 192 = 3. PR-3 depends on PR-4's deliverable — confirmed, decoupled. PR-3's success criterion named "host mstlink," which is PR-4's tool. The fix is a real distinction I'd conflated: reading the host's negotiated speed is unprivileged ( Thanks — all three were real, and the FEC one in particular was the exact §4d trap (a 50G reading standing in for a 100G fact) that the rest of this PR exists to document. |
…y failure mode review 67285 (claude/opus), both findings: - The PR proved a modeled authority false (byte 192 = 0x40, NIC 100G_2X) and left the stale row standing with the correction only in prose. Marked it ON THE CARRIER: an annotation on gunbc.spark.fabric_switch_observed fabric_leg_cable_observed says nic_supported_speeds is now WRONG post-recode (still says 50G_2X), that linked_speed_gbps: 50 stays true only by coincidence (switch-side blocker, not a NIC cap), names this the a_live_authority_name_carries_a_superseded_claim class, and states the trigger (the G12 event model supersedes the row rather than overwriting it). A doc note is not the mark; the carrier now carries it. - The credential/restore incident (GCP token expired mid-experiment, srv5 left forced-100G / NO-CARRIER with no in-session recovery path) was a discovered error class recorded only as G16 prose. Filed the row per DESIGN §4b: gunbc.recurring_failure_mode a_rollback_depends_on_a_credential_that_can_expire_mid_actuation -- invalid state, why it survives testing, the srv5 specimen, the discriminator (bites out-of-band per-step-credential actuation, not the modeled once-per-run path), rung (mitigatable), ceiling (eliminated by not actuating out of band), next-rung trigger (the modeled converge path becomes the only actuation path), and the review tell. The roster is gitignored and regenerates from the directory at compile. New row compiles green (claim_batch, the_new_failure_mode_row_compiles). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Both findings in review 67285 addressed in the latest commit. 1. Superseded fact left in prose — now marked on the carrier. You're right: the PR proved 2. Restore incident owes a Both were the right call — the superseded-authority one is literally the class that's already rostered, and the incident genuinely earned its own row rather than a markdown bullet. Thank you. |
review 67294 (claude/opus): the previous commit's `//` annotation was
itself a §4c violation -- it asserted a machine claim in prose ("so a
reader does not consume nic_supported_speeds as current") that no Accepted
program can read, while a value the commit itself calls WRONG kept
answering (§5: a wrong answer is a loud error, never a warning).
The honest value was already in the diff. Corrected the literal:
nic_supported_speeds now carries the post-recode mstlink Supported Cable
Speed (100G_2X, 50G_1X, 50G_2X, 25G, 10G, 1G), so the field is TRUE.
linked_speed_gbps stays 50 because the link still trains at 50G for a
switch-side reason, so the two fields are independently true. The
annotation is rewritten as honest rationale -- why the value is what it is
and that G12's event model will make it derived -- with no prose standing
in for a machine check. G12 supersedes a true reading just as well as it
would have a false one.
Verified nic_supported_speeds is read by nothing (only linked_speed_gbps
is consumed, by fabric_rail_desired and the witness, both unchanged); the
observed witness stays green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed in the latest commit — you're right, and my annotation-only fix was itself the violation. The Took your first resolution: corrected the literal to the post-recode truth. Verified Thanks — this was the right call. I'd tried to discharge a §5 debt with a §4c annotation, which is exactly the trap. |
review 67302 (claude/opus): two claims stood UNMARKED at their own sites with corrections elsewhere -- the recurring meaning-fork this PR keeps tripping on. - build-plan.md: "forced-both is what actually trains 100G on this hardware" was asserted as fact, and this PR's own log falsifies it (the one mstlink forced-both run stayed in Polling, no link). §4d: do not assert as deduced what is only inferred. Restated at log-supported confidence: forced-both is the MikroTik-required production CANDIDATE, the one run of it did NOT train, so PR-3 + PR-4 together let us RE-TEST it once the coding is fixed rather than achieve convergence by themselves. - actuation-log.md: "forced path is non-compliant for CR" (:130) and "VERDICT: 100G will not come up in any configuration" (:138) stood unmarked while their retraction sat 25 lines below. Marked both AT their sites -- struck through with a pointer to the mstlink re-test section -- so a reader hits the correction where the wrong claim is, not 25 lines later. Docs only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Both fixed in the latest commit. 1. build-plan §4d over-assertion. You're right — "forced-both is what actually trains 100G on this hardware" is asserted as fact and this PR's own log falsifies it (the one mstlink forced-both run stayed in Polling, no bilateral link). Restated at the confidence the log supports: forced-both is the MikroTik-required production candidate, the one run of it did not train, so PR-3 + PR-4 together let us re-test forced-both properly once the QSFP-DD coding is fixed — they don't, on current evidence, achieve convergence by themselves. That removes the false signal to a PR-4 worker that building the mstlink grant achieves convergence. 2. actuation-log unmarked superseded claims. The "forced path is non-compliant for CR" claim and the "VERDICT: 100G will not come up in any configuration" both stood unmarked at their sites while the retraction sat 25 lines below. Marked both at their sites — struck through with a pointer to the mstlink re-test section — so a reader hits the correction where the wrong claim is, not 25 lines later. This is the third time a review has caught me leaving a superseded claim standing with the correction elsewhere — it's a real habit in how I was writing this log, and co-locating is the fix. Thanks for holding the line on it. |
review 67308 (claude/opus): correcting the stale value in the previous commit grew a `String` leaf that hides named parts already modeled -- the link-mode set (extdeps.ethernet.link_mode LinkMode rows this module already imports), the reading instrument, and the date. "100G_2X, 50G_1X, ..." is the nicknaming §3 forbids and the anemic leaf §2 forbids, and the firmware/date suffix is the instrument-output transcription §6 forbids. The field is read by nothing (only linked_speed_gbps is consumed, by fabric_rail_desired and the witness), so the honest fix is to DELETE it, not enrich it into a List<LinkMode> that nothing would read (a richly modeled dead field is still a §3c dead field). Removed from the type and the data row; the "what the link reports" note now says the NIC advertised mode set wants a typed List<LinkMode> cited to its instrument and is not carried until a consumer needs it. The NIC-supported-mode observation (post-recode 100G_2X, mstlink) lives in the actuation log and lands typed when G12's event model gives it a consumer. Verified nothing else constructs FabricLegCableObserved or reads the field; the observed witness stays green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed — deleted the field rather than growing it. You're right on both counts: correcting the stale value in the prior commit grew a Since Verified nothing else constructs This closes the loop the earlier review (review 67294) opened — it offered delete-or-correct, I chose correct, and correcting turned out to grow the anemic leaf, so delete was the right call after all. |
…+ standing claim)
review 67317 (claude/opus): I marked the nic_supported_speeds deletion on
the carrier but left two other stale claims in the SAME file unmarked --
the "HONEST STANDING CLAIM" prose ("the coding does not attest the required
mode and the NIC refuses it today") and the primary_compliance_code: 11
(0x0B) eeprom rows for spark-a3ee/ac79. The recode falsified the prose and
the eeprom rows are a pre-recode snapshot, so a consumer of
fabric_leg_observation_for got the stale verdict with nothing on the
carrier saying so.
Swept the whole file this time rather than one claim per round:
- SUPERSEDED banner over the pre-recode narrative (:39-63): the coding now
attests 100GBASE-CR2 (byte 192 0x40), the "Cable speed not enabled"
refusal is gone, the live blocker moved switch-side. Kept as the
pre-recode reading rather than rewritten, because the fix is the G12
event model (PR-1), named as the trigger.
- The eeprom observation rows are marked as the 2026-09-08 pre-recode
acquisition. NOT re-valued: a receipt is a dated snapshot and overwriting
it falsifies the record; the post-recode reading is a new acquisition
that lands as an additional row under G12. Stated as a temporal fact
(these ARE the pre-recode coding; current is byte 192 = 0x40 per the
actuation log), not a machine directive to the reader.
Observed witness stays green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed — and you're right that I'd marked one stale claim in this file while leaving two others unmarked. I swept the whole file this time rather than one claim per round:
Observed witness stays green. This is the recurring pattern from the last few rounds and I own it: I'd been marking the claim I happened to be editing rather than sweeping the file. Done that now. |
review 67327 (cursor): my SUPERSEDED `//` banner on the eeprom rows was the §4c trap again -- the row is NOT a dated receipt, it is the LIVE plant reading (FabricLegEepromObservation has no acquisition timestamp, and .first() / fabric_leg_reading -> LegReadingTaken -> fabric_cable_plant consume it as current). So primary_compliance_code: 11 on spark-a3ee was a known-false LegReadingTaken -- silent wrongness on the plant path (§5) that a comment cannot discharge, with the true value parked in markdown (§6). Took the reviewer's option 1: re-valued spark-a3ee to the complete post-recode dump I actually read -- byte 192 = 0x40 = 64 (attests 100GBASE-CR2), date_code 260914 -- so the plant now answers the current coding. spark-ac79 keeps its last ACTUAL reading (11): the operator re-flashed it too but it was not re-read, and re-valuing it would fabricate an observation nobody took (the reviewer noted ac79 is fine to leave). The two legs now DISAGREE by coding, which the distinct-serial witness exists to keep representable, and the module's own note says the model must represent one leg recoded and the other not. The banner is replaced by a factual note (which leg is post-recode, which is last-actual), not a directive to the reader. G12's event model (PR-1) still lands dated multi-acquisition history and a re-read of ac79 appends rather than overwrites. All 7 fabric-switch witnesses green, incl. the coding-ceiling and two-legs-distinct claims. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed — you're right, and this closes the gap in my earlier reasoning. My SUPERSEDED Took your option 1: re-valued spark-a3ee to the complete post-recode dump I actually read — byte 192 = The banner is replaced with a factual note (which leg is post-recode, which is last-actual), not a reader directive. All 7 fabric-switch witnesses green, including the coding-ceiling and two-legs-distinct claims. This was the crux the whole |
Decision (operator asked me to choose): the actuation log had drawn seven review rounds, all against a blow-by-blow narrative that preserved every wrong turn in prose (forced-non-compliant then corrected, a verdict then re-tested, an FEC sweep, strike-throughs). That narrative is the liability; its value is three things -- the facts established, the exact commands run (the transcription source PR-3's converge is built from), and the verdict at witnessed confidence. Rewrote to those essentials (195 -> 76 lines). Each conclusion is stated once, correctly: host recode confirmed (and carried on the modeled carrier, not just here), the commands (switch REST + host mstlink + restore), the verdict (no bilateral 100G under any tested config; switch-side coding the leading hypothesis, NOT proven; substitution control is the isolating test), and cross-references to the failure-mode row, the gaps, and the build plan. Git history carries the exploration; the file is the current honest record. All cross-references to this file are by filename and still hold. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ionale)
review 67338 (claude/opus): re-valuing spark-a3ee to 0x40 falsified two
current-tense claims I did not sweep.
- fabric_switch_observed.dag: the FabricLegEepromObservation type annotation
still said "the two legs agree today", one carrier contradicting the new
block 18 lines below ("the two legs now DISAGREE"). §4c: an annotation may
not restate what the declarations structurally say, and this said it
wrong. Corrected: whether they agree is derived, and they now disagree
(a3ee re-read to 0x40, ac79 still at last pre-recode 0x0B).
- fabric_switch_desired.dag crs812_desired_fec(): the rationale "Clause 91,
the FEC the 100GBASE-CR2 attestation is conditional on" was true of 0x0B
(attests ieee_50gbase_cr2 RequiresClause91Fec), but code 64 attests
ieee_100gbase_cr2 FecUnconditional -- so my re-value falsified it. Fixed
the rationale: the conditional-on justification was for the pre-recode
coding; the real 100G FEC (RS(544,514)/KP4, gap G2, maybe not exposed by
the CRS812) is an open question, and the returned Fec91 is retained as the
provisional forced-DAC value, NOT asserted as correct -- decided by the
converge test (PR-3), deferred until the hardware links (§4d). Value
unchanged; comment only.
Assessment witness green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Both fixed — both are consequences of the a3ee re-value that I failed to sweep, and you're right that I applied the correct standard everywhere else and missed these. 1. The "two legs agree today" type annotation at 2. The Assessment witness green. This is the tail of the re-value: correcting a consumed data row propagates to every annotation and rationale that referenced the old value, and I should have swept both files in the same commit. Done now. |
Design + record for converging the CRS812 fabric lanes to 100GBASE-CR2 through a modeled path. No code — this is the design the credential/read/converge PRs implement, and the honest record of the manual actuation those PRs dissolve. Follows PR #11504 (the EEPROM read grant).
Context (what happened on the hardware)
The operator recoded the QSFP56 host ends with an FS BOX; PR #11504 landed the grant to read the leg EEPROM. This branch investigated the switch end:
192.168.1.240, RouterOS 7.20.8).0x0B→0x40, NICSupported Cable Speed: 50G_2X→100G_2X, advertises 100GBASE-CR2, former refusal gone.--link_mode_force -s 100G_2X), across every switch FEC mode. Host sits inPolling; switch reportsauto-init-failed/eeprom-checksum: badon the DD end.Verdict is stated at witnessed confidence: switch-side coding is the leading hypothesis, not proven. The isolating test is a hardware substitution control, not more configuration.
What's here
fabric-switch-actuation-log.md— the out-of-band actuation (operator-approved), the reviewer correction that MikroTik requires forced/autoneg-off (my "non-compliant" framing was wrong), a credential/restore incident (token expired mid-op, left srv5 down until re-auth), and the transcription source for the modeled apply.fabric-switch-100g-convergence-gap-analysis.md§6 — 16 modeling gaps (G1–G16) found by driving the real hardware: no autoneg axis, FEC enum can't express RS(544,514), live/two-ended link outcome unmodeled, no REST reader/apply, no switch credential, mstlink unmodeled,fabric_switch_observedstale, dispatch can't fan out, ad-hoc-curl scaffold to kill.fabric-switch-convergence-build-plan.md— the normal path, layered per DESIGN §3, credential mirroring spark bootstrap, and the PR sequence.A deliberate sequencing decision (§4d)
The read path is built first (safe, groundable in captured data). The converge apply is deferred until the hardware links at 100G, because its FEC/autoneg specifics are currently inferred, not witnessed — modeling the apply now would assert as fact what we haven't observed. PR-3's converge will correctly refuse/report
Pollinguntil the coding is fixed, which is the honest behavior.🤖 Generated with Claude Code