Commit Graph
11 Commits
Author SHA1 Message Date
arcattackandClaude Opus 4.8 2c6db6a2de Diag: speed-change investigation -- authentic analog throttle CONFIRMED, harnesses + gait probes (task #50)
Decomp workflow w0odszxro settled the speed model: the pod throttle was ANALOG-
CONTINUOUS (RIO Ranger, 800 ADC counts, 0.05 deadband; sole detent = snap-to-1.0
within 0.05 @004d196c).  '5 speeds' is FALSE -- the 1-5 keys are MFD mode pages;
the 0..5 stepper is HUD/radar zoom.  BONUS: throttleState@0x4a4 is a MISNOMER --
binary census proves it is the fall-contact surface material cache (0..7, init
2=Concrete), written only at knockdown; rename pending.

Empirical rule-outs (autonomous drive-sweep harness, this commit):
 - Record density: with the clock guard + incremental heading in, a per-frame
   continuous demand sweep measures IDENTICAL to constant throttle on position
   evenness ([repljit]), render heading ([rendhdg]), and gait cadence ([gaitev]).
 - Type-3 stomps: ~0 fire in sustained sweeps (only at launch) -- not the driver.
 - The 0.05-grid keyboard publish experiment is retained env-gated OFF
   (BT_GRID_LEVER) -- the ADC was ~continuous, so the grid is NOT authentic and
   gains nothing measurable; default publish stays continuous (authentic).

New tooling: BT_DRIVE_SWEEP[0] (forced-drive triangle sweep, optional through-
zero), BT_FORCE_STEP (0.05-grid variant), BT_GAITEV (per-frame leg-clip advance
+ state-flip + demand-change stats), [t3rx] (type-3 stomp trace).

STATUS: user still reports visible speed-change glitches in interactive play;
all harness metrics saturate at baseline -- next step is probes ON the user's
interactive session (their eyes + instruments on the same run).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:47:03 -05:00
arcattackandClaude Opus 4.8 93456be051 MP: FIX keyboard-driving peer skip -- non-pose records no longer kick the dead-reckon clock (task #50)
The discriminating user report: peer motion was smooth under the autonomous
harness but skipped when driven by KEYBOARD -- even pure walking / pure spinning.
The harness pins throttle/turn constant; the keyboard SWEEPS the throttle lever
every frame of a key-hold (mech4 sLever integrator), so mapper->speedDemand
changes every frame, and the speed-deadband gate (authentic exact !=) fires a
type-2 speed record EVERY FRAME for the whole accel/decel.  The base reader
Simulation::ReadUpdateRecord stamps lastUpdate=Now() on EVERY record (flagged
'HACK - should be based upon message->timeStamp' in the 1995 source) -- so each
type-2 SHRINKS the peer reckoner's projection span (nextUpdate-lastUpdate)
without refreshing updateOrigin: the position target jumps backward toward the
stale origin, the next pose record yanks it forward -> target oscillation every
frame during any input sweep.  Matches the session-long 'worst on accel/decel'.

FIX (mech.cpp Mech::ReadUpdateRecord): non-pose records (2,3,5,6,7,8) preserve
lastUpdate around the base call (keeping the real payload, simulationState).
Pose (0) and resync (4) keep their authentic clock behavior.  BT_T2_CLOCK
restores the old stamping for A/B.

REPRO HARNESS (mechmppr.cpp): BT_FORCE_SWEEP=<period> triangle-sweeps the forced
throttle 0.2..0.9 -- a type-2 record per frame, the keyboard-skip repro the
constant-throttle harness could never produce.

Verified A/B, autonomous circle+sweep (the keyboard regime):
  old clock:  worst frame spike 10.4x avg, path/net ratio 1.069 (backtracking)
  guarded:    worst 4.6x, ratio 1.0022 (no backtracking)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:12:52 -05:00
arcattackandClaude Fable 5 02cdfd6576 Torso: the TWIST goes LIVE -- electrical watchdog chain, centered crosshair, coherent controls (task #57/#58)
The MadCat torso twists, the view turns with it, and targeting follows.
Three reconstruction fronts closed:

THE ELECTRICAL WATCHDOG CHAIN (why the torso never powered up):
- PowerWatcher::UpdateWatch reconstructed (@004b181c, the REAL registered
  Performance -- PTR @0050f5fc; Ghidra missed the fn start): the watchdog
  MIRRORS the watched subsystem's electrical level (+0x278), brownout
  downgrade when gen output <= minVoltage% x rated.  @004b1804 relabeled
  ResetToInitialState (slot 10) -- the old "Simulation" tag was wrong.
- The factory watcher-CONNECT pass reconstructed (vtable slot +0x38,
  @004aee2c/@004b1a40 byte-identical, recovered from raw exe bytes):
  watchedLink.Add(roster[watchedSubsystem]) on the master node.  Was the
  SubProxy::Start() no-op -- every watchdog sat at 0 forever.
- MinVoltageScale = 0.01 (a 10-byte x87 literal @0x4b1924; was 1.0f =
  permanent brownout) and PowerWatcher's Derivation chains its REAL base
  HeatWatcher (the HeatableSubsystem stand-in broke IsDerivedFrom for the
  whole Torso/Searchlight/ThermalSight family).
- KB correction swept: derivation tag 0x50e604 = HEATWATCHER (not
  "HeatSink"); the btl4gaug heat-widget gate now tests it via the
  BTIsHeatWatcher bridge.

THE CROSSHAIR (task #58 forensics, 6-agent workflow + live probes):
- The VIEW is TORSO-MOUNTED: jointtorso -> jointeye -> siteeyepoint in
  every twist-capable .SKL; the camera + canopy ride the same hinge
  subtree through HingeRenderable's live matrix-stack compose -- ALREADY
  WORKING in the port.  The crosshair stays screen-centered (center IS
  the boresight); the twist reads on the tape carets/compass/radar.
- The real bug was the port's gBTAimX = tan(twist) slew (the falsified
  "body-mounted view" model): the camera already carried the twist, so
  the crosshair counter-slid to hull-forward and the fire ray with it.
  Deleted; the pick ray inherits the twist from the yawing eye basis.
- Two instrumentation traps documented (chase-eye-as-default-camera,
  BT_FORCE_TORSO clobbering real joints -> the hook now only fills
  unresolved ones); an over-correcting explicit eye compose was added on
  those false readings and retired the same day.

CONTROLS + REPLICATION:
- Q/E spring-center on release (the axis is a twist-RATE demand; the old
  hold-deflection model drifted forever); X also zeroes the axis and
  pulses the authentic torso Recenter (@004b6918).  M cycles control
  mode via the real CycleControlMode body.
- Torso update-record DIRECTION fixed: engine truth is Write=serialize /
  Read=apply; @004b6a78 is the READ (was mislabeled Write) and the
  missing WRITE @004b6a1c recovered from raw disasm (recordLength 0x1C,
  twist/vel/rate at +0x10/14/18) -- kills the replicant's 0xCDCDCDCD
  -140-degree ghost twist.
- Marching-ghost desync: 4 Standing-case guards zero stale reverse
  cycleSpeed (negative cadence passed the <= ZeroSpeed stop gate).
- Kill credit rerouted to the OBSERVED killer (lastInflictingID ->
  killer's player link) -- kills count, target K/D populates.

KB: subsystems.md (watcher chain), multiplayer.md (record direction),
combat-damage.md + gauges-hud.md + cockpit-view.md (torso-mounted view
re-correction), decomp-reference.md (new addresses + tag fix),
open-questions.md (dead capability-roster loops 2-4, snapshot CD read).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 13:27:49 -05:00
arcattackandClaude Fable 5 092408041c Cockpit: the CONFIG-MODE weapon-regrouping session + the live-play fire fixes (tasks #6+#11)
TASK #6 -- the pod's in-cockpit weapon regrouping, fully reconstructed and
live-verified (hold-configure -> tap fire button -> toggle membership ->
release-commit):
- MechWeapon handlers id 9 ConfigureMappables @004b9550 / id 10 ChooseButton
  @004b95b8 (binary table @0x511860; the old "Myomers fns" mislabel swept)
  + the GetMessageHandlers() accessor chain through Emitter/ProjectileWeapon/
  MissileLauncher/GAUSS/PPC (empty per-class sets swallowed dispatch).
- Mapper vtable truth: +0x38 EnterConfiguration / +0x3C ExitConfiguration /
  +0x40,+0x44 AddOrErase evt/dir.  No "secondary vtable @0050f498", no
  "CreateTemporaryEventMappings" virtual (RP-name drift; swept incl CLASSMAP).
  L4 Enter/Exit rebuilt complete: StartMappableButtonsConfigure (the
  NonMapping 0x10000 <-> Mapping 0x8000 mode flip + the gauge's active-weapon
  latch) + the held-button re-arm + the 4 fire-button temp maps; only the RIO
  mapper implements the toggle (Thrustmaster no-ops = can't regroup).
- MechSubsystem +0xE8/+0xEC corrected to controlDestination/controlMessageID
  (ex hostEntity/subsystemId2 mislabel); MechWeapon ctor defaults the
  destination to &fireImpulse (@004b99a8).
- ConfigMapGauge state loop reconstructed (PE-recovered DAT_00518eb4 table;
  buttonGroup GetMapState sampler -- the "needs ModeManager" guard rationale
  was wrong).  Finding [T1]: the shipped binary NEVER enables this gauge (no
  SetColor caller) -- authentically dormant; BT_CONFIGMAP=1 is the dev enable.
- Dev harness: HOLD 'G' opens the session (BT_CONFIG_SLOT picks the weapon);
  BT_CONFIG_TEST scripts a headless verify.  @004afbc4 corrected to its real
  Fail-trap body (the guessed AddOrErase(NULL) body would corrupt groups).
- Bonus [T1]: the binary MechWeapon ATTRIBUTE table has ELEVEN entries
  (PercentDone..WeaponState) -- "TriggerState is the only one" was wrong.

TASK #11 -- the user-reported live-play regressions (both real bugs):
- PHANTOM FIRE: the mech4 bring-up shot block painted an explosion at the
  victim on its OWN 0.3s cadence whenever fire was held -- desynced once the
  authentic recharges landed.  Retired (the real impact visual flows from
  each discharge via the messmgr SubmitExplosion).
- WEAPON BRICKING (the "cuts out" bug): the Loading->Loaded snap window
  (+-0.01 around seekV) assumes the pod's LOCKED 60 fps; one port dt-spike
  jumps it, the byte-verified >1.0 clamp (_DAT_004ba830=0) zeroes readiness,
  and the weapon sticks in Loading at level ~10000 forever (observed live).
  Fixed with pod-frame (1/60s) sub-stepping of the binary's own Loading tick
  -- also fixes the I^2R integral over-heating generators on big steps.
  NEW GOTCHA CLASS recorded: reconstruction-gotchas #12 (frame-pacing trap).
- Duty-cycle measured (max-rate autofire): generators equilibrate in the
  degradation band (recharge stretch ~3.5-4.4x), the FailureHeat breaker
  never trips solo, PPCs sustain ~11.8-damage full-charge fire.  The slow
  kill pacing and recharge gaps are the AUTHENTIC heat economy; the pilot's
  counters (this regrouping UI, generator reassignment, coolant valves) are
  the reconstruction queue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 19:39:35 -05:00
arcattackandClaude Fable 5 afefaeece5 Mech: THE 0xBD3 UNTANGLE -- real SubsystemMessageManager in [0x10d], the mapper's one true home is roster slot 0 (task #7)
Binary census [T1]: mech+0x434 has exactly 2 writers (ctor init + factory
case 0xBD3) and ONE reader (@0x4b984b in MechWeapon::SendDamageMessage
@004b9728) -- pure message-manager semantics, nothing mapper-like.  The
factory case now builds the real SubsystemMessageManager (ctor @0049bca4,
0x130, ConsolidateAndSendDamage Performance); the misbuilt MechControlsMapper
squatter is evicted.  Every mapper consumer re-pointed to MappingMapper()
(roster slot 0 = the binary's **(mech+0x128); SetMappingSubsystem @0049fe40
touches ONLY slot 0 -- its [0x10d] mirror removed).  Non-viewpoint mechs get
a slot-0 demand LATCH (base mapper, [T3] accommodation -- the binary leaves
slot 0 NULL off-viewpoint but never drives/animates those paths; ours does).
Verified: solo drive+gait clean; MP replicant gait through the latch (full
run lifecycle); 3x kill/respawn cycle with type-6 records on the observer.
Remaining (task #7 tail): the messmgr's consolidated TakeDamageStream send +
weapon-path routing (@004b9728 real body).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 14:16:27 -05:00
arcattackandClaude Fable 5 c9f0c2a7f1 MP: the Mech-level update records @0x4a0c2c/@0x4a1232 -- all 9 types byte-exact (task #1)
- Writer transcribed from the recovered disasm; reader rewritten from
  part_012.c with every Wword absorber promoted to named engine/port members
  (updateOrigin/updateVelocity/projectedOrigin/projectedVelocity/nextUpdate/
  lastUpdate + bodyTargetSpeed/latches/alarms).  Wire sizes verified live:
  0x14/0x20/0x2c/0x78.
- movementMode UNIFIED with Simulation::simulationState (binary mech+0x40 =
  StateIndicator@0x2c currentState) -- death/limbo/airborne now replicate in
  every record header.  Three mislabels of the same binary fns retired:
  SetInstanceFlags + RequestActionFlags -> Mech::ForceUpdate (updateModel |=
  mask, 0xfe03 disabled filter); IsNetworkCopy -> IsDisabled.
- Senders wired byte-exact: gait transitions Force(8), knockdown Force(1|0x20),
  death Force(1|0x40), Reset Force(0x1f) + binary zero-set, perf-loop
  deadbands (speed type 2, orientation type 4, heat type 7).
- 2-node verified: types 2/3/4 flow while driving; kill -> type-6 record
  (simState=9) -> the OBSERVER's replicant runs the wreck sink loop with no
  double death transition; respawn 0x1f burst snaps + un-wrecks the peer;
  walking replicant un-regressed (run 12, cycle tracking); solo clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:38:49 -05:00
arcattackandClaude Fable 5 a110041a70 Fix "can't turn in MP": pilotArray[1] overrun stomped controlMode
User report from the first live 2-window session: throttle worked, A/D turn
did nothing.  [mppr] showed the input REACHING the mapper (stickX=-1) but
turnDemand=0 and controlMode = pointer garbage (73583232 / 217478632 --
different per instance), from frame 1, MP only (solo mode=0).

Hunted with a cdb hardware write-breakpoint (ba w4 armed at ctor time on
&controlMode, compiled offset +0x128 from the [mode-ctor] probe).  Caught the
writers red-handed: MechControlsMapper::BuildPilotArray / FillPilotArray.

ROOT CAUSE -- a shrunk-span array: the binary reserves a FIXED 10-slot pilot
block @0x15C..0x183 ((pilotArrayBuilt@0x184 - 0x15C)/4 = 10); the recon
declared `Pilot *pilotArray[1]` ("variable length"), so every write past
slot 0 stomps the members declared after it.  In MP, FillPilotArray wrote the
PEER's Player pointer into slot 1 = over controlMode -> the turn shaping
dispatched on pointer garbage -> turnDemand 0.  MASKED in solo: the zero-loop
overrun wrote 0 there, and 0 == BasicMode.  This was ALSO the real cause of
task #48's "turnDemand zeroes out in -net" observation (worked around then
with the direct goto-turn; attribution corrected in the KB).

Fix: pilotArray sized to the binary's own 10-slot span; ctor zeroes all
slots; BuildPilotArray clamps pilotCount to capacity (local + 9 remotes; an
8-pod game fits).  Diagnostics kept (BT_MODE_LOG ctor probe; [mppr] line now
prints mapper/&mode).

VERIFIED: MP session holds mode=0 throughout, turnDemand flows nonzero, the
mech turns (heading -1.33) and closes on the peer; solo kill chain intact.
KB: new "shrunk-span array" gotcha (reconstruction-gotchas 5) with the cdb
ba-w4 recipe; multiplayer.md task-#48 note corrected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 18:16:46 -05:00
arcattackandClaude Fable 5 d4e139a0d9 Gait v5: display+travel from the LEG channel (kills the stutter class)
User-reported recurrence of "legs stutter and lose sync".  Live [sync] showed
advSum/legSum drifting 5->92 during walk-up churn, then locking.  Reproduced
headlessly (BT_FORCE_OSC throttle feathering + BT_FORCE_TURN + the new
per-frame BT_SYNC_LOG probe) and root-caused in two parts:

- SEED: the bring-up turn-in-place trigger arms only the LEG channel, so the
  walk re-entry lands one frame apart -> a persistent clip phase offset.
- AMPLIFIER: with offset clips the two end-of-clip callbacks fire on different
  frames; a demand change landing between them picks DIFFERENT next states
  (one channel winds down, the other keeps walking) -> opposite-phase churn
  (observed bs=6 ls=7 -- body on walk-R, leg on walk-L).

Under v4 (display+travel = BODY) the out-of-phase LEG pose showed through on
every frame the body didn't write joints (Standing/wind-down) = the visible
stutter/pop.

DISASM GROUND TRUTH (neither Advance fn has a static decomp caller; found by
byte-scanning the CODE section for e8 calls):
  - master perf (0x4a9b5c gap) -> AdvanceLegAnimation @0x4aa399 (air @0x4aa388)
    -> -dist/dt into localVelocity (+0x1cc): the LEG drives LOCAL travel and
    (writing last) the displayed pose;
  - IntegrateMotion (0x4ab1c8, body advance @0x4ab312, caller FUN_004ab430 =
    the projected-origin updater) -> -dist/dt into projectedVelocity (+0x2a0):
    the BODY is the dead-reckoning PROJECTOR -- locally invisible.
  v4's reading of FUN_004ab430 as the travel source was wrong.

FIX: advance body FIRST (projection; its writes get overwritten), leg LAST
(displayed pose); travel = legAdv under the two-channel split.  Display ==
travel through the LEG by construction -- body-channel drift can no longer
become visible, structurally (not by input-symmetry luck).

Verified: trn+feathering repro clean; straight drive locked (adv==proj);
solo goto=enemy kill chain intact; MP 2-node drive-to-range cross-pod kill
intact (241 hits, DESTROYED); no crashes.  KB corrected (locomotion.md roles
+ P3_LOCOMOTION.md v5 entry).  New gated instruments: BT_SYNC_LOG,
BT_FORCE_OSC.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 16:25:49 -05:00
arcattackandClaude Fable 5 48b17750e5 HUD reticle + weapon pips LIVE: dpl2d 2D display-list port (task #35)
- dpl2d API fully recovered from the binary recorders (@487f34-488630):
  opcode model (points/lines/polyline/circle/color/width/matrix/push-pop),
  CallList = INLINE include (state persists to caller), centered coordinate
  frame (unit = half viewport height). game/reconstructed/dpl2d.cpp rework.
- BTReticleRenderable ctor @004cc40c transcribed with the authentic
  calibration (originX .35, originY .25, scaleY .5, 0..1200m right range
  ladder, bottom heading tape, FUN_004cd938 tick ladders, lock rings,
  turn arrows); range caret slides from the live target range fed by the
  mech4 targeting step (BTSetHudTargetRange).
- Weapon pips: the binary gate is IsDerivedFrom(0x511830 =
  MechWeapon::ClassDerivations) [T1: part_014.c:5386 hard-aborts on missing
  weapon attrs; part_012 counts + roster ORs capabilityFlags@+0x334] so ALL
  7 BLH weapons register (3 lasers + 2 PPCs + 2 MissileLaunchers). Pip A
  (lit, authored PipColor) on TargetWithinRange, else dark ring B.
- AddWeapon @004cdac0 store map corrected to the verified order
  (part_014.c:4827-4837); both state attrs are literally named
  "SimulationState" (strings @51d526/51d577) -> weapon simulationState.
- Mech roster this[0x1ef] renamed poweredSubsystems -> weaponRoster
  (0x511830 is MechWeapon, not PoweredSubsystem=0x50f4bc); derivation-tag
  table added to context/decomp-reference.md.
- Draw hook BTDrawReticle after the 3D scene, cockpit view only. Binary
  Execute @004cdcf0 is an un-exported gap -> Draw dynamics [T3], tracked
  in context/open-questions.md with the blx_cop canopy + PNAME pip meshes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 20:05:44 -05:00
arcattackandClaude Opus 4.8 0060a3e1ca gauge wave P2b: build the Comm KILLS/DEATHS pilot roster (PilotList)
PilotList (keyword "pilotList") was PROSE-ONLY, so the Comm surface showed only
the baked btcomm.pcx labels.  Reconstructed all 7 functions from part_014.c:
3156-3434 (Make/ctor/dtor/BecameActive/TestInstance/Execute/DrawMechIcon), with
the 8x(x,y,layoutMode) layout table DAT_0051af88 PE-parsed exact from BTL4OPT.EXE.
Draws ONE roster slot/frame (round-robin) from the viewpoint mech's cockpit-mapper
pilot roster.

- Roster FEED: new BTResolveRosterPilot(slot) bridge in mechmppr.cpp (a complete-Mech
  TU) resolves the viewpoint mech's ControlsMapper (subsystemArray[0]) -> GetPilot;
  btl4gau3.cpp reads the returned pilot at raw BTPlayer offsets.  The mapper's
  FillPilotArray already fills the roster (pilotArray[0]=GetMissionPlayer,
  [1..]=FindGroup("Players")).
- KILLS = killCount@0x27c (real; ScoreMessageHandler increments it in combat).
- DEATHS: the binary reads pad_0x280 which has NO writer anywhere (a shipped dead
  field -> perpetual 0).  FIX per "if it doesn't work, fix it": read the real
  deaths counter Player::deathCount@0x200 (VehicleDeadMessageHandler increments it)
  so DEATHS is meaningful in MP.
- DrawMechIcon: App+0xC8 name-bitmap cache is unwired (same deferral PlayerStatus
  uses) -> LookupPlayerNameBitmap returns NULL -> the tinted name box (never an AV).

Dropped the bogus x,y from the header ctor (positions come from DAT_0051af88).
/FORCE-safe (all vtable slots real; link log clean, no unresolved PilotList/
BTResolveRosterPilot).  Verified DBASE+dev gauges: the Comm surface now renders the
live local pilot row (KILLS 0 DEATHS 0 + name box; 0/0 authentic in solo -- the
combat scoring feed that moves them is Phase 3), combat un-regressed (DESTROYED),
0 crashes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 17:24:24 -05:00
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00