Commit Graph
20967 Commits
Author SHA1 Message Date
orezraeyandClaude Opus 5.5 ecae349210 Merge main into fix/libc-gethostname-measured-ps5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 16:41:23 -03:00
Yunus Shaikh 6f36f29ea3 fix(shader): answer phis and null bases in a trimmed plan as the program does
A plan copies a branch condition only as far as the evaluator reads it,
and an operation the evaluator does not read is kept without its
arguments. Two questions the walk asks still read below such a leaf.
ResolveInvariantPhi compares a phi's incoming values with
EquivalentValue, which follows their arguments, so two leaves with the
same operation looked equal in the copy where their arguments differ
in the program: a phi whose incoming values differ only below a vector
load resolved in the plan and not in the program, and the plan decided
a condition the program leaves open. LoadedFromMemory looks for a read
from memory anywhere below a raw read's handle, so a handle that
reaches memory only below a leaf lost it in the copy: a read from a
null base counted as a null root, and its condition stayed open where
the program decides it.

ownPlanValues now checks both after it copies. Each phi it copied in
part must resolve in the copy to the copy of what it resolves to in
the program, and each raw read's handle must be loaded from memory in
the copy when it is in the program. A phi that differs is copied whole;
a handle that differs keeps the arguments along its shortest path to a
read from memory (its whole closure if that path is already kept), and
the copy is made again. The checks only add values, so the loop ends,
at worst with the whole copy. IsMemoryRead names the operations that
LoadedFromMemory and the path both stop at.

Tested: agc_shader_memory's verifyPlanCopyAnswers walks a phi whose
incoming values differ only below a vector load, and a read from a null
base whose handle reaches memory only through a select arm the active
mask never takes, through the plan's tape, the plan's interpreter and
the program's own walk, and all three agree. Without the checks the
plan decides the first condition and leaves the second open.
2026-10-23 21:40:20 +02:00
Yunus Shaikhandfablevoid d257635bae test(shader): check what a resource plan keeps of its branch conditions
The plan of a hand-built program keeps exactly the 40 values its two
branch conditions and two descriptor sources read: none of the 64
additions under the vector load that the conditions reach only through
operations the evaluator does not read, which the whole copy kept (170
values). Its walk decides both conditions and resolves both sources as
the program's own walk does.

The plan of a compute program whose branch condition reads a scalar
load at an address taken from vector data keeps the same number of
values for vector chains of 1, 16 and 64 steps before the load. This is
fable-void's agc_driver_resource_plan_retention from cca1f5a8d, which
runs on his DeviceTableFixture; here the program is built from raw
words and read through GetResourcePlan.

The pruning case also takes the checks of his cb13fecfe: a condition on
a select of a vector load is dropped (main's MayEvaluate drops it), the
readable conditions stay, and no plan value keeps use lists or spare
operand capacity.

Co-authored-by: fablevoid <[email protected]>
2026-10-23 21:40:20 +02:00
fablevoid 402f891787 fix(shader): keep only what a resource plan's conditions can evaluate
A resource plan owns copies of the IR values its run-time evaluation
reads: the descriptor sources, the SRT reads, the uniform fills, and
the branch conditions that tell which images a dispatch can reach.
Below a scalar load from memory, the copy took every value the load
depends on, whether the evaluator can compute it or not. A condition
that reads memory after vector work (a load predicated by a vector
compare, an address computed from vector data) brought the program's
whole vector graph into the plan: in a title's programs 2.4 million of
2.6 million retained values, about 500 MiB, belonged to twelve or so
conditions per program.

Below a condition, the copy now follows only what the evaluator reads:
the arguments of values it can compute, and for a load from memory the
words of its descriptor and its offset; a value the evaluator cannot
compute is kept without its arguments, which is what evaluating it
needs (it does not evaluate). Descriptor sources keep their whole
closure, which the device image pre-pass walks.

Tested with a new test (agc_driver_resource_plan_retention): the plan
of a program whose branch condition reads a scalar load at an address
taken from vector data now keeps the same number of values for vector
chains of 1, 16 and 64 steps before the load (84, 114 and 210 before);
the device table, written image, buffer descriptor, memory and SRT
range and shader disk cache tests pass; in a title's corpus the plans
of 314 programs hold 40 thousand values instead of 837 thousand; the
corpus recompile with SPIR-V validation has no invalid module.

Resolved onto main: the retention test runs on DeviceTableFixture.hpp,
which main does not have, so the test and its CMake line are left out
here; the next commits test this on main.
2026-10-23 21:40:20 +02:00
fablevoid 9796a23046 fix(shader): copy only what the SRT evaluator reads of plan branch conditions
ExtractPlan copied the whole argument closure of every control-flow
condition into the plan. The draw-time walk (SrtDescriptorEvaluation)
uses a condition only when the evaluator computes it, and an operation
outside the evaluator's set ends the evaluation without reading its
arguments. For conditions on vector loads, image results or values
carried around loops the copy reached most of the program, and none of
it was ever read.

Detail::Evaluator::Reads names what the evaluator reads of a value:
nothing (an operation it does not evaluate, an immediate), its
arguments (the operations it evaluates, identities, phis, and the pairs
CompositeExtract reads through), or its whole closure (a raw read, whose
handle LoadedFromMemory walks). EvaluateInst returns early for a value
it reads nothing of, so the two cannot drift apart. ownPlanValues still
copies descriptor sources, SRT reads and fill values whole, and copies
a condition only as far as Reads goes: an operation it does not read is
copied without its arguments. The pure and guarded flat slots are
computed before the copy, from the same values as before.

Evidence: a title that registers about 5,700 shaders at load held
24.1 M copied IR values in its plans (about 5.4 GiB by value size), of
which 2.1 M were reachable from descriptor sources, SRT reads and fills
(counted by a local report over the recompiler's source map).

Tested: agc_shader_memory gains verifyPlanConditionPruning: a condition
on a load with a 64-addition address keeps the load as a leaf and none
of the additions, and conditions read through an extracted pair and
through a raw read still evaluate. It fails without the change. Full
ctest passes.

Resolved onto main: Reads is a static member of BasicEvaluator next to
MayEvaluate, and its operation list is main's evaluator's
(evaluatedArguments adds BitCount32, FindILsb32 and FindUMsb32; the
undefined values, which main never evaluates, read nothing). The
EvaluateInst guard reads the node's value, so it covers the compact
plans too. ownPlanValues now runs after the flat slots and before the
compact plan, and gives a value it keeps without arguments an empty
operand list, so the leaf drops the operand capacity main's IrValue
constructor reserves. Main's MayEvaluate already drops the condition on
the vector load, so the test checks that it is gone.
2026-10-23 21:40:20 +02:00
Dean 61ad086100 Merge pull request #10189 from LeandroLP23/fix/main-push-builds-finish
ci(build): let a running main build finish before the next push's build starts
2026-10-24 08:39:49 +13:00
JAB-devandClaude Sonnet 5.5 31aaf42381 docs(debt): restore the Packed 16-bit textures entry from main
The merge resolution had dropped its storage image sentences, which main keeps and this branch does not change.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 21:35:16 +02:00
SandstromPLandClaude Opus 5.5 9d4909b0bf test(agc): match ANYPS5_GPU ignoring case in two more fixtures
PooledBufferRange and NativeMultisampleDepth match ANYPS5_GPU against
device names with std::strstr and std::string::find, which are
case-sensitive, while the driver and docs/dev/ENVIRONMENT.md match it
ignoring case. A request the driver accepts, such as ANYPS5_GPU=nvidia
for an NVIDIA GPU, matches no device in them: PooledBufferRange keeps
the first device and then refuses it with "selected device does not
match ANYPS5_GPU", NativeMultisampleDepth finds no device. Both report
a skip, or fail under ANYPS5_REQUIRE_VULKAN.

They now pick their device through SelectFixturePhysicalDevice, with
the driver's rule. That also changes two choices on machines with more
than one device: without ANYPS5_GPU, PooledBufferRange ranks devices by
type and needs Vulkan 1.1 instead of taking the first discrete one or
the first device, and with a request NativeMultisampleDepth takes the
first match instead of the best-ranked one, as the driver does. The
selection CPU test covers the second case.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 01:04:11 +05:30
SandstromPLandClaude Opus 5.5 98f9a89877 test(agc): honor ANYPS5_GPU in the fixtures that open their own Vulkan device
Seven AGC fixtures create their own Vulkan instance and take the first
enumerated device or choose one by device type, without reading ANYPS5_GPU:
PresentationPass, DepthPlaneGuestLayers, DepthStorage,
DepthSurfaceLastWriter, OversizedDescriptorSets, PartiallyResidentSnapshot
and SparseBufferHoles. With a name that matches no device they still pass
on whichever GPU came first, so a run meant for one GPU can report results
from another.

They now pick their device through one shared helper with the driver's
rule: among Vulkan 1.1 devices, the first whose name contains ANYPS5_GPU
ignoring case, otherwise the first of the highest-ranked device type. A
name that matches nothing throws with the device names, which these
fixtures report as a skip, or as a failure under ANYPS5_REQUIRE_VULKAN.
A CPU test covers the selection and the error message.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 01:04:11 +05:30
krishalivaibhavandClaude Sonnet 5.5 8cf0a39f86 fix(agc): let imports that cannot write guest memory keep the watch armed
ImportWatched opened a blanket host-write window over the whole import range on
macOS, so every block in it read as CPU-written even when the import stored to
none of it, which failed agc_write_tracking (#10344). Add importMayWriteGuest,
defaulting to the previous behaviour. The two GuestBufferMemory callers create
Vulkan imports in-process and never write the range through a kernel API, so
they opt out and only pages actually stored to are marked.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-24 01:03:32 +05:30
Bram910 d9fde17a3d fix(tools): validate trace summary JSONL records 2026-10-23 21:32:52 +02:00
Swag 43315af395 Merge upstream/main into feat/libressl-error-queue
Co-Authored-By: Claude Opus 5.5 <[email protected]>

# Conflicts:
#	core/libs/prx/libSceLibreSsl/CMakeLists.txt
#	docs/dev/debt/libSceLibreSsl.md
2026-10-23 15:27:06 -04:00
JAB-devandClaude Sonnet 5.5 aeb000e7fb Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 21:26:58 +02:00
cadenasynyster 0a238f9e49 fix(libc): keep a rename source lookup error ahead of a destination loop
On Windows, rename converted ENOENT or ENOTDIR to ELOOP when either parent directory was below a symbolic link loop. A missing source, or a source below a non-directory, paired with a destination through a loop then reported ELOOP. FreeBSD 11.4 kern_renameat returns the failed source lookup before it examines the destination. A loop below the source still gives ELOOP, and a loop below the destination gives ELOOP only when the source lookup succeeded.

guest_filesystem gains the missing-source and non-directory-source-prefix cases paired with a looping destination, for rename and sceKernelRename.
2026-10-23 21:26:38 +02:00
SuarezPM 0ef31bad75 fix(shader): emit type-correct zero into table merge phis
Table accessors returning scalar uint fed the merge Phi a 4-wide
zero, failing SPIR-V validation with SPIRV_TOOLS on. Use ZeroResult
like the unsupported path.
2026-10-23 21:22:29 +02:00
SuarezPM 548267bfa3 feat(shader): support 32-bit image atomics through keyed image tables
Table T#s keyed at runtime no longer fault on image_atomic_*32: the
table operation stays supported, elements carry the atomic flag through
dedup into the descriptor binding, and the table path binds AtomicView
like the direct path. 64-bit atomics stay unsupported, packed and BY
formats stay unsupported, and the debt entry records the relaxed
Device-scoped emission and the remaining gaps.
2026-10-23 21:22:29 +02:00
Himansh Raj d6433a6006 build: compile the shared libc headers, thread priority and three tests on macOS
A macOS build of main failed 49 objects. Most included
libc/include/FileStream.hpp, whose global-namespace ::feof_unlocked and
::ferror_unlocked do not exist there (they are macros in the macOS SDK).
On macOS:

- FileStream.hpp calls feof_unlocked and ferror_unlocked unqualified.
- ExportMacros.hpp adds the leading underscore Mach-O gives C symbols to
  both names in APS5_EXPORT, so the .set alias resolves.
- ThreadPriority.cpp has no rtkit or RLIMIT_RTTIME; "high" asks for the
  user-interactive QoS class and "rt" for a Mach time-constraint policy
  (period 1 ms, computation 0.5 ms), documented in ENVIRONMENT.md.
- Formatting.cpp maps the SysV va_list builtins to va_list, and
  GuestContentSearch.cpp and GuestNpWebApi2.cpp include
  <initializer_list>.

With these, 16 objects still fail on macOS; each is in a file changed by
an open macOS PR. Linux and Windows compile the same code as before.
2026-10-24 00:50:46 +05:30
SamandClaude Opus 5.5 8067758412 fix(agc): recognise the copy kernel as Demon's Souls 01.007.000 compiles it
The buffer copy HLE recognises its copy kernel (dst[i] = src[i % period]
for i < count, count and period read from a parameter buffer) by a hash
of its first 38 instruction words. Demon's Souls PPSA01341 01.007.000
ships the same kernel compiled to a different instruction sequence, with
the same descriptors and parameter layout, so every one of its copies ran
as a GPU dispatch and later CPU reads of the copied bytes waited for it.
That hash is now accepted too.

The new agc_driver_period_copy test runs that kernel through the driver:
with the HLE the linear cases must take a copy path, a period below the
count and a launch larger than the count needs must not, and every case
must produce dst[i] = src[i % period]. agc_driver_period_copy_no_hle runs
the same cases as shader dispatches (APS5_NO_COPY_HLE=1), so both paths
are checked against the same results.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 21:20:37 +02:00
Himansh Raj 0f15e1baa3 fix(libc): find guest image pages through dyld on macOS hosts
macOS has no link.h or dl_iterate_phdr, so GuestAllocations.cpp did
not compile there. On macOS the main and loaded guest images are found
with _dyld_image_count, _dyld_get_image_header and
_dyld_get_image_vmaddr_slide, and their pages come from the LC_SEGMENT_64
load commands' initial protections. The file-backed writable image scan
stays Linux-only. Linux and Windows are unchanged.
2026-10-24 00:48:30 +05:30
JAB-devandClaude Sonnet 5.5 8d54357e79 Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/agc-4-4-4-4-partial-writes
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 21:18:00 +02:00
cadenasynyster 0aef357591 fix(libkernel_sys): report ELOOP from mkdirat through a Windows symlink loop on a descriptor
On Windows, mkdirat with a directory descriptor and a relative path that goes through a symbolic link pointing to itself reported EIO. CreateDirectoryW fails with ERROR_CANT_RESOLVE_FILENAME for such a path, and the error mapping had no case for it, so it fell through to GuestEio. FreeBSD fails the lookup with ELOOP. The path form of mkdir and openat with the same descriptor already return ELOOP. ERROR_CANT_RESOLVE_FILENAME now gives ELOOP.

guest_kernel_sys gains a Windows check with a file-type and a directory-type self-loop: mkdirat through the loop returns ELOOP and mkdirat of the link itself still returns EEXIST. The check is skipped when the host denies symbolic link creation.
2026-10-23 21:17:33 +02:00
Adrià d7948b09f9 Merge pull request #8563 from JAB-dev/feat/agc-4-4-4-4-color-target
feat(agc): render 4_4_4_4 UNORM color targets through packed R16_UINT exports
2026-10-23 21:12:19 +02:00
DragostandCursor 0415d01996 fix(libSceAvPlayer): reconcile the audio clock when EOF arrives late
The last audio frame can be consumed before the decoder marks EOF, so the in-pull check never sees an exhausted stream. Rebase once EOF is visible with an empty queue, and hold the producer in the test so both orderings stay deterministic.

Co-authored-by: Cursor <[email protected]>
2026-10-23 21:11:23 +02:00
orezraeyandClaude Opus 5.5 f47c0cc250 Merge main into docs/librtc-dos-time-measured-ps5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 16:11:17 -03:00
Zenodeon 5785179785 fix(agc): mirror only the unimported tails of registered heaps 2026-10-23 23:06:38 +04:00
Adrià 8cc82c85bf Merge pull request #6469 from QRMOE/fix-low-guest-address-mappings
fix(memory): honor low guest mapping hints
2026-10-23 21:06:11 +02:00
Dean Galvin 19dd43f0d8 test(libScePad): drop the unimplemented-throw asserts added by #9995
The tests for scePadSetLotusEnableIrKey, scePadSetLotusDisableIrKey,
scePadVirtualDeviceDisableButtonRemapping and scePadVirtualDeviceGetRemoteSetting
only checked that an unimplemented call throws. A test of that kind fails as
soon as someone implements the function, so it pins the absence of a feature
rather than behaviour. Tests should cover real behaviour and argument
validation.

This removes those asserts, the Throws helper and the declarations they were the
only users of. The rest of the pad test is unchanged.
2026-10-24 08:03:40 +13:00
Adrià ea695358ee Merge pull request #8527 from eliasbruno124-dev/fix/host-import-settle-order-20261020
fix(agc): order deferred import settles with main-queue accesses
2026-10-23 20:59:54 +02:00
Dean Galvin 13727eebd1 Merge main into perf-D2-v47 2026-10-24 07:59:40 +13:00
hypermistandClaude Opus 5.5 e813b210bc Merge remote-tracking branch 'upstream/main' into feat/libc-sce-v2-thread-sync
Kept both sides of GuestLibcThreads.cpp: main's ThreadHelpers test and this PR's VersionedSync test, both called from main().

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 07:59:37 +13:00
orezraeyandClaude Opus 5.5 2d33e51c45 fix(libScePad): answer scePadOpen's user, index and port checks as measured on a PS5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 15:58:45 -03:00
Claude 24bbc6d5f8 fix(libSceLibreSsl): leave the AES key untouched when key setup fails
AES_set_encrypt_key zeroed the whole schedule and set rounds before it
checked the key length, so a refused call changed the AES_KEY. As in
LibreSSL 2.5.4's aes_core.c, it now returns -1 or -2 before writing
anything and writes only the 44, 52 or 60 words the key length needs.

The test fills the key with a sentinel and checks, for both setup
functions, that refused calls leave all 244 bytes unchanged, that
AES-128 and AES-192 keep the 16 and 8 unused words, and that every
written word matches the FIPS-197 appendix A schedules and the
decryption schedules computed independently and with OpenSSL 3.0.13.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-23 18:56:08 +00:00
roboterspinne da511cb29c refactor(relinker): remove relocation types validation already rejects
ValidationPolicy rejects R_X86_64_GOT32, PLT32, GOTPCREL, 32S, GOTPCRELX
and REX_GOTPCRELX for every DT_RELA and DT_JMPREL entry before the Linux
patcher runs, so the R_X86_64_32S case of the fixed-base relocation
list cannot be reached. It was the only user of R_X86_64_32S, and the
other five constants have none. Remove the case and the six constants;
no behaviour changes.
2026-10-23 18:55:45 +00:00
ntamas94andClaude Opus 5.5 d44c823834 feat(libSceJson2): implement sce::Json::Array::operator=
Copy the source array into this and return this, as the console does
(measured on a PS4 Pro, firmware 10.71). Knowledge is Power: Decades
imports it; the inventory stub threw NotImplemented.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 20:53:04 +02:00
Adrià ad19afc31e Merge pull request #8518 from JJenkx/fix/srt-guard-condition
fix(shader): decide resource branch conditions from their uniform operand
2026-10-23 20:50:37 +02:00
Bram910 5bf97cce6b fix(tools): validate ELF import table file ranges 2026-10-23 20:48:28 +02:00
HQasperandClaude Opus 5.5 c17591d425 feat(libSceLibreSsl): implement the low-level AES functions
AES_set_encrypt_key, AES_set_decrypt_key, AES_encrypt, AES_decrypt,
AES_ecb_encrypt, AES_cbc_encrypt, AES_cfb128_encrypt and
AES_ctr128_encrypt threw. They now follow LibreSSL's aes.h and its CBC,
CFB-128 and CTR mode code on the caller's 244-byte AES_KEY: key setup
returns -1 for null arguments and -2 for a key length other than 128,
192 or 256 bits, CBC pads a partial final block with the IV and writes
the whole block, CFB and CTR resume from *num, and the CTR counter
carries across all 128 bits.

The test checks the FIPS-197 appendix A and C vectors and the SP 800-38A
CBC, CFB-128 and CTR vectors, split across calls, in place and with
partial blocks.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-23 18:48:20 +00:00
Adrià 1e1ab77684 Merge pull request #8495 from yabanana/fix/borrowed-memory-regions
fix(shader): reject temporary owners for borrowed memory regions
2026-10-23 20:47:29 +02:00
thuanquangandClaude b6b5b80374 docs(shader): say that the f32 compares do not throw in f32 denormal modes 1 and 2
Co-Authored-By: Claude <[email protected]>
2026-10-24 01:45:52 +07:00
orezraeyandClaude Opus 5.5 dd27146c27 fix(libkernel): keep the TCP flag and IP receive options a PS5 accepts
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 15:45:11 -03:00
thuanquangandClaude 2e874e6a4b docs(debt): say that a raw compute program takes the live RSRC1 float mode
Co-Authored-By: Claude <[email protected]>
2026-10-24 01:44:52 +07:00
thuanquangandClaude f9b5b9767c docs(shader): drop the stale lavapipe skip from the 16-bit interpolation entry
Co-Authored-By: Claude <[email protected]>
2026-10-24 01:44:22 +07:00
thuanquangandClaude 3a8199606a docs(debt): say when agc_driver_f64_fma_subnormals skips
Co-Authored-By: Claude <[email protected]>
2026-10-24 01:44:20 +07:00
thuanquangandClaude 92579f545a docs(debt): correct two stale f64 denormal statements
The shader float mode entry said "Other f64 arithmetic does not model
these denormal controls". On main, v_add_f64, v_mul_f64, v_floor_f64,
v_ceil_f64, v_fract_f64, v_frexp_mant_f64, v_frexp_exp_i32_f64,
v_div_fixup_f64, the f64 compares and ds_min/max/cmpst_f64 read the
f16/f64 denormal field, and each has its own entry. The sentence now
names the f64 arithmetic whose translation still does not read it.

The v_floor_f64 entry said its modifier run used 16 of the 23 measured
values. The run's list holds 13 of them plus -1.5, 2.75 and 1 - 2^-53.

Co-Authored-By: Claude <[email protected]>
2026-10-24 01:43:29 +07:00
Adrià e78acf4bda Merge pull request #8352 from akkadbakkad89/feat/libc-dinkumware-locale-threads
feat(libc): export _Thrd_yield
2026-10-23 20:41:39 +02:00
orezraeyandClaude Opus 5.5 062dc00385 fix(libkernel): join and leave multicast groups as measured on a PS5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 15:38:52 -03:00
orezraeyandClaude Opus 5.5 802bcc8d61 fix(libkernel): share a port between SO_REUSEPORT sockets on the host
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 15:38:45 -03:00
Adrià 606999f3ab Merge pull request #7937 from DavidSamir/feat/libkernel-jit-shared-memory-macos
feat(libkernel): JIT shared memory on macOS hosts
2026-10-23 20:37:27 +02:00
JJenkx f4c543528e fix(agc): preserve pending depth for readable protected planes 2026-10-23 14:37:09 -04:00
orezraeyandClaude Opus 5.5 4aaa0dbf38 docs(libkernel): record that the other flexible map flags are accepted here
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 15:35:45 -03:00