`testflight-triage` already covers the local `.xccrashpoint` corpus,
including the two Organizer traps, but the triage agent and command
named only two destinations: a single crash file and a Sentry/ASC
aggregate. A corpus of local bundles fell between them and looked
uncovered from the places a reader starts.
Writing a catalog from a script: the layout Xcode expects, measured on a
970-key catalog where a generic JSON writer produced a 26,531-line diff
that buried the actual translation. The two Apple writers order the
top-level keys differently — the editor by `localizedStandardCompare`,
`xcstringstool` by code point — so a sync over an editor-maintained
catalog re-sorts every key.
`xcstringstool` is the headless path in and out of a catalog, through
`xcrun`. It prunes: an entry missing from the `.stringsdata` is marked
stale if it has translations and deleted outright if it has none, exit 0
and no warning, which makes `--skip-marking-strings-stale` the guard
worth knowing before the first run. It re-emits the canonical layout
only when it has something to write.
Key styles: the source string is `localizations[sourceLanguage]` if
present, else the key itself — a tool has to handle both, and
`sourceLanguage` is not always `en`.
Homographs: a comment gives a translator context, it does not split a
key. One English word used for two concepts is one entry with one
translation and merged comments; each meaning needs its own key with the
English in a default value.
Terminology: the simulator runtime ships Apple's own localized bundles,
which are the exact UI strings, alongside hundreds of AppShortcuts
phrase files — more precise than a support page for the form of a
string, though the support pages still win for what a user says aloud.
Vertical bars: items join one only from inside a system-managed
container, so the same `.bottomBar` items in a bare full-screen cover
render as a horizontal capsule while `toolbarVerticalEdge` still reads
an edge. Hosting a `NavigationStack` in a custom full-screen layer costs
two things worth knowing up front — it paints an opaque background
unless the content inside it sets `.containerBackground(.clear, for:
.navigation)`, and it hands that content the window's safe-area insets
back even under an ancestor's `.ignoresSafeArea()`.
In the bar, a system Toggle or Button ignores `.foregroundStyle` and
`.opacity` and a `.contextMenu` on one does nothing, so a control with
on/off/unavailable states needs a custom view opted in with
`.axisBehavior(.verticalPreferred)`, which keeps its styling and its
context menu. `visibilityPriority(.high)` works on those custom items.
`toolbarVerticalEdge` reports the system's preferred edge whether or not
a bar is visible, and is set before any toolbar item exists, so gating a
layout on it is not circular.
Testing: the 27.1 runtime creates only iPhone Duo, poses are Device
Hub-only, and screenshots default to the inner display — black while
the device is closed.
uikit-modernization: iPad refuses `requestGeometryUpdate` under the
windowing model, and the error handler is the only signal.
Taps: document `--tap-style`, the measured matrix of what each style
activates, and the rule that a tap prints a success line whether or not
anything happened — so the effect is what to assert, never the output.
Selectors resolve to an element's accessibility activation point, so a
view whose frame is skewed gets tapped off target and still reports
success. The session hint and the simulator-tester agent were telling
readers to call `axe tap` bare, which is the inert form; both now point
at `xcui tap`, and the agent's long-press example used a flag `axe tap`
does not have.
Rotation: `devicectl device orientation set` is verified on iPhone and
iPad, with screenshot dimensions as the check. It is a silent no-op on
iPhone Duo, and an app's own `requestGeometryUpdate` is refused on iPad
under the windowing model, so a test that needs landscape rotates from
the host.
Capture: `--mask alpha|ignored|black` and what each shows, plus naming a
display on a two-display device — simctl takes a port UUID, devicectl a
uniqueId, and the default capture is the inner display even when it is
closed and dark. `recordVideo --mask alpha` is accepted but renders
black.
Also: with several simulators booted every device verb now needs
`--udid`, and a broken code fence in device-control-ref.
AXe's default tap style sends a simulator tap that SwiftUI controls
ignore while AXe still prints a success line. Measured on Xcode 27.1
with AXe 1.8.0, across iPhone 17 (iOS 27.0) and iPhone Duo (iOS 27.1):
neither a Button, a List row, a Button inside a List, a Menu, a row of
an open Menu nor a TabView tab activated under the default or the
`simulator` style, and `--tap-style physical` activated all six. The
same default left system alerts on screen while `dialog accept`
reported them handled.
`tap` and the `dialog` accept/dismiss taps now supply the physical
style unless the caller picks one, and an AXe older than 1.7.0 — which
has no `--tap-style` — is named as the cause instead of surfacing as an
unknown-flag failure.
With more than one simulator booted and no `--udid`, every device verb
now exits 2 and lists each booted device's UDID, name and runtime,
rather than driving whichever sorted first while reporting success.
`doctor` reports that list, fails its gate in that state, and leaves
`booted_udid` empty, because nothing may be targeted until the caller
chooses.
- ConcentricRectangle guidance for custom surfaces and bottom sheets
- tvOS SwiftData storage no longer promised as durable
- Foreign keys on new columns without a table rebuild
- concurrency-auditor stops flagging UIKit subclasses
- test-failure-analyzer reports non-isolated main-actor calls as build failures
test-failure-analyzer said calling a @MainActor member from a non-isolated
test becomes a runtime data race under -swift-version 5. It is a compile error
in every language mode, so it breaks the build rather than flaking. Say so,
note that construction depends on the mode, and drop a redundant await from
the corrected example. The agent's docs page no longer calls it a data race.
Verified: the call is rejected under Swift 5 (minimal and complete checking)
and Swift 6; the corrected example compiles cleanly and the broken one fails
with the quoted error.
concurrency-auditor Pattern 1 reported every UIViewController and UIView
subclass without @MainActor as CRITICAL. Both classes are NS_SWIFT_UI_ACTOR,
so their subclasses already inherit main-actor isolation. Scope the pattern to
ObservableObject and other UI-state classes, skip it when the target's
SWIFT_DEFAULT_ACTOR_ISOLATION is MainActor, and list UIKit subclasses as a
false positive. The audit command page's example output now matches.
Verified: an unannotated UIViewController/UIView subclass called from a
nonisolated function fails to compile against the iOS 27.1 SDK; a plain
ObservableObject does not.
database-migration offered only an app-enforced relationship or a table
rebuild, and database-schema-auditor told readers a foreign key could never be
added by ALTER. A new column can carry one: ALTER TABLE ... ADD COLUMN ...
REFERENCES, or GRDB's t.add(column:).references(...). With foreign keys on,
SQLite requires that column to default to NULL, so it starts with no orphans.
Document the route and its decision-tree branch, scope the rebuild to
existing or NOT NULL columns, and make the auditor's searches catch GRDB's
t.add(column:) form. The companion page's rules now match the skill.
Verified: sqlite3 3.54.0 (the iOS 27.1 SDK's version) enforces the key,
refuses a non-NULL default, and cascades only to the deleted album's rows;
GRDB 7.11.1 source for add(column:), references, notNull and defaults.
The tvOS section of swiftdata.md said Caches was the one directory the system
may purge, recommended an Application Support store URL for durability, and
called CloudKit sync optional. Every local directory on tvOS can be deleted
while the app isn't running, as the rest of the suite and axiom-swift's tvOS
skill say. Make iCloud the source of truth and the local store a cache the app
can rebuild.
The Corner Concentricity section named only sheets, glass containers, widgets
and custom containerShape as containers. Apple's ConcentricRectangle
documentation also counts the device's screen: a view that extends to the
display's rounded corners resolves concentric to the hardware, so a custom
surface should never look up the screen's corner radius itself.
Add that rule, a custom bottom-sheet recipe matching Apple's Notes Format
sheet (fixed top corners, concentric bottom corners, not zero), and what
concentricCornerRadii (OS 27) is for: radii without drawing, for Canvas,
animations and other custom surfaces. The companion reference page gains a
prompt and an index entry.
Verified: the new block compiles against the iOS 27.1 SDK at iOS 26.0 and
27.1 targets with no diagnostics.
Pattern 5's consuming close() closed the descriptor and then let deinit close
it again. Add discard self, and move the usage into a function, since a
top-level let is a global that can't be consumed.
Pattern 4 said consume only moves ~Copyable values. It ends any local
binding's lifetime; only bitwise-copyable types get the "has no effect"
warning and stay usable.
Verified: close() now runs once (previously deinit's second close failed with
EBADF); compiler probes for non-trivial copyable, trivial, and ~Copyable values.
MPMediaItemArtwork's request handler is imported without @Sendable, so a
closure written inside a @MainActor type inherits main-actor isolation, and
Swift 6 traps at its entry when MediaPlayer calls it off the main thread.
Capturing the image by value did not prevent that. Mark both handlers
@Sendable and correct the explanation: @Sendable removes the trap, and the
value capture keeps the body from reading main-actor state.
Verified: the previous shape stops with SIGTRAP when invoked from a
background thread; the @Sendable form returns normally. The edited blocks
compile against the iOS 27.1 SDK.
Track.album carried deleteRule: .cascade while Album.tracks cascades too, so
deleting one track deleted its album and, through it, every sibling track.
The NoteTag junction example in swiftdata-migration.md cascaded both of its
to-one sides the same way, and never compiled: Note and Tag had no
initializer.
Drop the cascade from the to-one sides (the default .nullify applies),
declare the junction's inverses, and add the missing initializers.
Verified: deleting one of two tracks now leaves 1 album and 1 track (was 0
and 0); removing one tag from a note keeps every note and tag (was all
deleted). The edited blocks compile against the iOS 27.1 SDK.
The Route 2 rebuild copied rows with an inner JOIN, so any track whose
album_name was NULL or matched no album was left out of the copy and then
deleted by DROP TABLE. PRAGMA foreign_key_check reports nothing, because the
rows are simply gone. Use LEFT JOIN so unmatched tracks survive with a NULL
album_id, and say to carry every kept column and compare row counts.
Also note that inside a GRDB registerMigration the raw PRAGMA/BEGIN lines do
not apply: the migrator already owns the transaction and, with the default
foreignKeyChecks: .deferred, runs the migration with foreign keys off and
checks them right before committing.
Verified: the published block keeps 3 of 3 rows in sqlite3; the inner-JOIN
form keeps 1.
Per-beta probe on Xcode 27.1 beta (27A9269, swiftlang-6.4.0.34.1), macOS and iOS:
every documented Swift 6.4 feature still holds, Continuation escaping-resume is
still rejected at SIL (limitation restamped through 27.1), and mapKeyedValues and
stdlib FilePath remain absent. One arrival: withTemporaryAllocation (OutputSpan
form) probes present, documented in the performance skill with a compile-verified
snippet.
The resize auditor's window-request check now says why a value-based gate is
insufficient: supportsMultipleWindows is true on both displays once the scene
manifest opts in — measured on the 27.1 Duo simulator — so it cannot tell you
which display you are on.
Verified: probe tables in the research notes; the new snippet compiles at the
27.0 floor.
The design suite still said the talks left supportsMultipleWindows on Duo
unstated. It now records the measurement: with UIApplicationSupportsMultipleScenes
set, the value is true on the outer display too, so it reports the scene manifest
rather than the display — the new-window affordance needs the system control to
hide itself off the inner display.
Verified: measurement in the research notes; the build regenerates the
distributions and the docs.
Moving the app to the right half reports the same size classes as the left —
compact width / regular height — and toolbarVerticalEdge flips from .leading to
.trailing, so each half's bar sits on its outer edge. The hub and the probe
results now carry both halves.
Verified: hub compiles 15/15; measurement in the research notes.
Measured on the Duo simulator (iOS 27.1, Xcode 27.1 beta): a Split View half
reports compact width / regular height — the same width class as the outer
display — and the bar follows the app's outer edge (toolbarVerticalEdge reads
.leading in the left half). The hub's truth table, its split-view guidance, and
layout.md now carry the measured values instead of "not stated", and the
multitasking bullet notes the half's layout class.
The same run (already reflected in the gate guidance) showed
supportsMultipleWindows tracks the scene-manifest key rather than the pose:
true with it on both displays, false without it, and unchanged across open/close.
Verified: hub compiles 15/15; probe log, no-key control, and both measurements
recorded in the research notes.
The hub said the talks left supportsMultipleWindows on Duo unknown and that iPhone
reports false. Measured on the 27.1 Duo simulator: with UIApplicationSupportsMultipleScenes
set, the value is true on the closed outer display and the open inner display alike, and
it does not change as the device opens or closes; without the key it is false. The
guidance now says the value tracks the manifest, notes that it cannot distinguish the
displays, and points at UIWindowScene.ActivationAction for an affordance that hides
itself where new windows are not available.
The same run confirmed inner portrait is regular/regular with toolbarVerticalEdge nil,
and the outer display is compact/regular with trailing — matching the truth table.
Verified: hub compiles 15/15; probe log and the no-key control recorded in the
research notes.
Apple shipped the iOS 27.1 SDK and it contains every iPhone Duo API the tech talks
announced, so the hub (axiom-swiftui skills/iphone-duo.md) and the camera reference
(axiom-media) present them as compiling code instead of attributed names. Each 27.1
call carries `@available(iOS 27.1, *)` with its pre-27.1 path, and the 27.0-era
"announced, may not exist" framing is gone. The hub also gains the UIKit side of the
camera-capture accessory (`UISceneAccessory.cameraCapture(sceneConfiguration:)` plus
`registerSceneAccessory(_:)`), which the talk-era tables had no spelling for.
Two rules changed rather than merely confirmed. Preview mirroring is overridden only
when a camera's position and direction disagree; the old text had the app take over
mirroring on every camera switch. Apple's new Technology Overview, HIG page, and
camera articles also add the hero-image extension under a vertical bar, pane-local
controls, overlay-arrangement geometry while folded, and the games screen-fill rule,
all folded in here. The Swift 6.4 deferred-feature table is re-scoped to 27.0 and
27.1 after re-probing both entries.
Verified against Xcode 27.1 (27A9269, iOS SDK 24A94403): the 22 Duo probes flip FAIL
to PASS, the hub's 15 Swift blocks compile at the target floor, the Duo simulator
device type creates against the iOS 27.1 runtime, and the toolchain delta is
additive-only and entirely Duo. Verified: probe 22/22, hub compile 15/15, hook tests
144/144, unit tests 524/524, docs build.
StoreKit and App Intents: `.nonRenewing` → `.nonRenewable`, `@unknown default`
over struct-backed enum-likes (seven switches), `Product.PurchaseResult`
qualification, `needsValueError`, `negativePhrases` typing, `@Parameter(default:)`,
and the SK1 deprecation (iOS 18.0) that no file recorded. The IAP auditor's two
grep patterns that cannot match real Swift are replaced, and the promoted-purchase
detector now targets `PurchaseIntent.intents`.
Runtime: the iOS 16+ simulator does register for remote notifications on
Apple-silicon/T2 Macs; a widget's push path is `WidgetPushHandler`, not
`PKPushRegistry`; `ActivityViewContext` has no `relevanceScore`; `ActivityState.pending`
is iOS 26+; the widget frequent-updates floor is 16.2; `BGTaskScheduler.supportedResources`
is a class property and the submission strategy is `.queue`; timer state-machine
violations trap as EXC_BREAKPOINT/SIGTRAP on arm64 (EXC_BAD_INSTRUCTION is the
Intel lowering); the BackgroundTasks console subsystem is `com.apple.backgroundtasks`.
Privacy and data: required-reason codes corrected against Xcode 27.2's `.xcprivacy`
schema (disk space is 85F4.1/E174.1/7D9E.1/B728.1; C56D.1 is the third-party-SDK
UserDefaults wrapper, AC6B.1 the MDM managed-app-configuration reason); Apple-hosted
asset-pack quota is 200 per app; the inaccessible `unifiedMeContact` and the
macOS-only subgroup operations are gone.
Files in `axiom-performance`, `axiom-security`, `axiom-shipping`, `axiom-ai`,
`axiom-watchos` and `docs/` carrying the same claims were corrected in the same pass.
Cursor, Codex and MCP distributions regenerated.
Verified: `npm test` static gate clean; every changed block extracted from its saved
file and compiled at the file's floor.
`claude-code.json`'s skills array is generated from SKILL.md frontmatter, so the
router description corrected in 19208d3a left the committed manifest carrying the
old trigger text — and `/axiom:ask`, which is generated from that array, with it.
The unit suite's drift guard caught it; four consecutive Test Suite runs went red
on nothing else.
Regenerated with `scripts/set-version.js` at the current version, so no version
change is involved: the diff is the description, the generated `ask.md`, and the
Cursor mirror.
Verified: npm run test:unit (519/519) and node scripts/leak-scan.ts (0 errors).
Two defects found by reviewing the previous round's own output.
`carplay-navigation-ref.md` quotes the guide's lane-guidance instructions, which
are written against the Objective-C API: "return a symbol style of
CPManeuverDisplayStyleSymbolOnly for the maneuver." The quote is faithful, but
that constant has no Swift spelling — the Swift form is `.symbolOnly` — so a
reader copying it out of a verbatim quote gets a compile error. The quote stays as
the guide wrote it; the Swift spelling is now noted beside it.
`camera-auditor`'s Pattern 2 search list included
`UIDeviceOrientationDidChangeNotification`, which does not exist in Swift at all.
As a text search it matched only legacy Objective-C-style code, so it could never
fire on a modern app — the same dead-detection-pattern class as the interruption
names corrected earlier, and missed by every previous round. The replacement is
checked against a three-file fixture: the old pattern matched only the legacy
file, the new one matches both spellings, and neither matches the control.
Cursor, Codex, inlined-auditor and MCP distributions regenerated.
Verified: npm test (static validation clean).
Nine passages in the CarPlay files were quoted as verbatim from the CarPlay
Developer Guide while carrying June 2026 page citations, but the wording was the
February 2026 revision's. An earlier pass relabelled the citations and re-derived
the page numbers without requoting the text, so anyone checking a quotation
against the cited page would find different words there.
All are requoted against the current 2026-06-08 revision. Two are whole-sentence
replacements rather than word swaps: the June guide's section is headed "Touch
gestures" and never uses the word "multitouch" anywhere, and the maneuver-metadata
guidance is reworded there.
A sweep of the neighbouring lines found eight further instances of the same two
classes — quotations that had elided words, or closed with a period a sentence the
guide continues — in the same three files.
Separately, the note in `camera-capture.md` about raising the quality ceiling said
it turns on optical image stabilization unconditionally; the header makes that
conditional on the active format's `isHighPhotoQualitySupported`.
Cursor, Codex, inlined-auditor and MCP distributions regenerated.
Verified: npm test (static validation clean).
An independent review of the audit's own fixes found defects the fixes had
introduced or left behind, and the hand-written docs pages — which restate many
of the same claims and are not generated from the skills — had not followed the
corrections.
Fixes that were wrong or incomplete:
- The paused-player elapsed fix was correct only where it was measured.
`playerTime(forNodeTime:)` returns nil whenever the player is not playing —
paused, stopped, or never started — and falling back to the lock screen's
dictionary republished the *previous item's* elapsed on a track change. It now
keeps an app-owned value, reset when a new item loads.
- "Other request types, hand-pose among them, still succeed" is false: measured
across eleven Vision requests, only hand-pose and text recognition run.
Barcodes, animal, body pose, human rectangles, saliency and feature print all
fail to build an inference context, and an order-reversed control on a second
device showed the failure is request-specific, not context exhaustion.
- `teardownCommands()` was left defined and called from nowhere. Two
`isEnabled = true` writes contradicted the file's own rule that registering a
target enables a command by default. The Bluetooth option legend that produced
a recording-recipe straddle still omitted that A2DP is output-only routing.
- Two citations pointed at the wrong guide page, one range omitted the page
holding its section's last step, and one quoted a sentence the guide does not
contain.
The docs sweep found fifteen stale claims across the pages mirroring this suite,
including the automatic-passthrough mechanism the audit disproved, a fabricated
`prepare()` timing figure, and a fabricated set of diagnostic percentages.
`photo-library`'s PNG/JPEG/HEIC split is now measured rather than asserted:
`Image.importedContentTypes()` and `exportedContentTypes()` are both
`["public.jpeg", "public.png"]`, with HEIC and HEIF absent.
Cursor, Codex, inlined-auditor and MCP distributions regenerated.
Verified: npm test (static validation clean).
Every claim checked against the iOS 27.2 SDK and Swift 6.4 — camera, photos,
audio, haptics, ShazamKit, MusicKit, Now Playing, CarPlay, DockKit, screen
capture — with blocks extracted verbatim from the files, compiled individually,
and measured where the claim is behavioural. 25 files, ~13.3k lines, ~408 blocks.
Several published examples cannot compile as shown. `SHSignatureGenerator.signature(from:)`
is static-only, and four call sites invoked it on an instance — including the
file's own "RIGHT" example. `AVProVideoStorage.isBusy` does not exist; the busy
surface is `busyReasons`. `AVCapturePhotoOutput.AppleProRAWQuery` appears nowhere
in the SDK, and the exposure sentinels are `AVCaptureDevice` members, so the
leading-dot spelling in argument position never resolved. The deferred-photo-proxy
delegate parameter is optional, or it fails the protocol's requirement. The
`shazam custom-catalog` invocations used flags the shipping binary rejects.
Two measured claims were the opposite of what the suite taught. Mic input is not
"always 44.1 kHz" — it is the hardware format, 48 kHz on the measured device — and
iOS does not deliver bit-perfect USB DAC output by default: a 96 kHz source renders
at 48 kHz unless the session's preferred sample rate is set. Both files contradicted
themselves 100 lines further down, where the correct advice already sat.
Other corrections: AHAP has no `Metadata` key and the framework drops it silently;
`automaticallyPublishesNowPlayingInfo` was misspelled; `SHLibrary.default.items` is
main-actor isolated; a published `deinit` calling a main-actor method could not
compile, and its replacement left the teardown unreachable while the checklist still
demanded it; CarPlay has 11 app categories, not 10 (video apps arrived at iOS 27),
and 7 universal guidelines, not 8 — with 76 Developer Guide citations re-derived
against the June 2026 edition, whose page numbers differ from the February one the
files cited.
The camera auditor's interruption detection matched three notification names that
exist in no AVFoundation spelling, so it reported every file containing
`AVCaptureSession` as missing observers. The auditor is generated, so the fix landed
in `agents/camera-auditor.md`.
Cursor, Codex, inlined-auditor and MCP distributions regenerated.
Verified: npm test (static validation clean).
Every claim checked against the iOS 27.2 SDK and Swift 6.4, with blocks
extracted verbatim from the files, compiled individually, and — where the claim
is behavioural — rendered or run. 543 blocks scanned across 26 files.
The suite's debugging guidance quoted output that cannot appear. `Self._printChanges()`
prints underscore-prefixed physical names whose depth depends on access level
(`__count` for a private `@State`, `_a` for an internal one), ends every line with
a period, and comma-joins causes onto one line. The advertised `MyView: count
changed` never appears, so the line cannot be grepped out of a console — and the
file omitted `@identity changed`, the marker Apple documents for the state-reset
symptom the file exists to diagnose.
Elsewhere the published fix did not fix the problem:
- The animation guidance for displaying a counting integer does not animate.
Measured with both arms in one run: the plain `Text` body evaluated once, at the
final value, while the file's own `Animatable` view evaluated 76 times.
- ScrollView's `.padding()` vs `.safeAreaPadding()` pair was wrong on all three
counts — both produce identical frames on a safe-area device, and only
`.ignoresSafeArea()` reaches the edge.
- A "conditional ChartContent crashes below 27.0" gotcha names a warning that is
emitted at no deployment target and no language mode; its workaround compiles
as a no-op.
- A `@State` deferral claim holds at the audit floor and is false where the file
says it applies: below iOS 17 the private case silently reverts to eager.
APIs that do not exist in any version were removed or corrected: `PreviewTrait.fixed`,
`@TimelineEntryBuilder`, `@ContentStateBuilder`, `toolbarCustomizationBehavior`,
`usesTextKit2`, `writingToolsResultOptions`, `TableAlias` as a protocol. Search is
bottom-aligned by default from iOS 26, not hidden on scroll. `@MainActor` on a
Codable `@Observable` model is the cause of its conformance-isolation failure, not
the concurrency safety the file advertised. And `simctl … booted` silently targets
whichever device is up — on a host with a stray booted simulator it verifies that
device's screen and exits 0.
Auditor procedures were corrected at their sources in `agents/`: thirteen grep
patterns could never match their target, including `.navigationTitle()` in a
UX-flow auditor, which reports clean rather than broken.
Verified: pre-deploy --static clean; inlined auditors, Cursor render, and audit
areas all current; 543 blocks swept before and after with no compile regressions.
Every claim in axiom-data checked against the iOS 27.2 SDK, Swift 6.4, and the
pinned third-party versions (sqlite-data 1.12.0, StructuredQueries 0.39.2,
swift-sharing 2.10.1, GRDB 7.11.1, realm-swift 20.0.5). Every code block was
compiled individually and the behavioural ones were run — on simulators, against
real stores, and through the system sqlite3 whose version and compile options
match the platform's.
The suite's guidance was wrong in ways that cost data rather than time:
- A chunked importer ended with an unscoped `delete(model:where:)` over an
always-true predicate. It did not compile, and adding the missing `try` would
have made it delete the entire store — 2,000 imported rows plus a pre-existing
unrelated row, measured. The compile error was the only protection.
- The migration file denied that SQLite can add a foreign key to an existing
table, forbade the table rebuild that is the documented route, and recommended
a PRAGMA that is inert inside a transaction — which the same file mandated.
Following it left orphan rows that `PRAGMA foreign_key_check` cannot detect,
the state the suite's own auditor rates CRITICAL.
- The storage reference gated must-save data on
`volumeAvailableCapacityForImportantUsage` and refused to write; Apple's own
documentation for that key says to attempt the write regardless.
- The tvOS storage claim denied that the directories exist and that local data
survives. A simulator probe showed a local-only store keeping every row across
relaunch and reboot; nine files carried the absolute and five cited the
corrected file as their authority while contradicting it.
Also corrected: APIs that exist in no version of their framework
(`@Attribute(.indexed)`, `addColumn(ifNotExists:)`, `migrator.hasBeenMigrated`,
statement `.fetch(_:)`, `.filter`, `TableAlias` as a protocol,
`ResultsSectionCollection`); quoted diagnostics the compiler never emits; an
`@Model` initializer rule the suite documented in one file and violated in
eleven; a `perform` removal that introduced a data race; and the expired
Realm Device Sync migration premise, written in the future tense after its
2025-09-30 shutdown.
Auditor procedures were corrected at their sources in `agents/`, since a dead
detection pattern reports clean — `@Model struct` cannot compile, so the pattern
that advertised it could never fire.
Verified: pre-deploy --static clean; 1,004 sub-skill pointers resolve across 344
emitted Codex files; Cursor output matches a deterministic full render.
The Quick Reference row read "nothing local is persistent" — an absolute that a
tvOS 27.2 simulator probe falsifies. A local-only store kept every row across
terminate, relaunch, and a full device reboot, so local data does persist; it is
simply not guaranteed.
Line 136 of the same file already carried the accurate form, leaving the router
contradicting itself. Both now say "no guaranteed-persistent local storage",
which is the phrasing tvos.md uses.
The fix pass corrected tvos.md in eight places — the core principle, the platform matrix,
the anti-rationalization bullets and the storage section all now say that tvOS has no
guaranteed-persistent local storage, and that the directories exist but none can be relied
on once the app is not running. The router was not updated, so axiom-swift contradicted
itself: tvos.md said the Documents directory exists, and SKILL.md said "no Documents
directory" in three places, including the anti-rationalization row a reader is most likely
to act on.
That is the same class the last review pass caught — a claim corrected in one file and
left standing in another — so it is worth noting that the fix pass cannot see it by
construction: each agent is scoped to one file, and the file that disagrees is never in
scope.
Also verified in this pass, against their sources rather than on report: no "no Documents"
claim remains anywhere in the suite; tvos.md's "§3" pointer resolves to its Storage
Constraints section; and the four mixed-era WWDC numbers the suite cites all return 200.
Verified: 519/519 unit tests, pre-deploy --static clean, distributions regenerated.
Third suite of the corpus audit. 7 files, 3,181 lines, 99 code blocks, audited by four
agents plus the three small files by hand. Compiles at the iOS 18 floor with -emit-sil
(never -typecheck alone, which cannot see the ownership checker) and runs on iOS and tvOS
27.2 simulators where the claim was behavioural.
Two findings were invisible to any compiler and both sat on the suite's core promises.
tvos.md taught that tvOS has no Documents directory and that all local storage is Cache.
Verified on a tvOS 27.2 simulator: the directory is returned, it exists, writes succeed,
and the file survives terminate + relaunch. Library/Application Support is returned as a
URL but does not exist until created, so the table's "Exists?" column was inverted for
both rows. The section now teaches the real constraint — no guaranteed-persistent local
storage — and the prose and table agree.
deep-link-debugging.md presents `simctl openurl` as the unattended primitive behind
/axiom:screenshot and the simulator-tester agent. It is not: on a simulator that has not
approved the scheme once, the first call raises a modal confirmation, exits 0, and
delivers nothing, so the follow-up screenshot captures the alert. Reproduced on a virgin
device and on an already-booted one with the app reinstalled; fixed with a verified
first-run pre-approval step.
Also: transferable-ref.md claimed the importing closure cannot await — it is `async
throws` and the block compiles clean, so the whole workaround was unnecessary — and its
"RIGHT" pattern did not compile and, repaired naively, silently dropped the value it
fetched. The queryItems helper offered as the safe alternative to force-unwrapping trapped
on a repeated key. ownership-conventions.md taught that `borrowing` avoids a copy (same
SIL; the default already borrows) and that `consuming` invalidates a copyable value (only
`~Copyable` does), and quoted three diagnostics the 6.4 compiler never emits. tvos.md
taught subclassing AVPlayerViewController and the player gesture recognizer that the WWDC
session it cites says to avoid. swift-modern.md claimed SwiftUI does not re-export UIKit;
its umbrella header does, on both iOS and macOS.
The fix pass was told to compile and run blocks extracted verbatim from the edited file
rather than probes written alongside — and for the first time in this audit the harness
caught its own work: three bugs in the ownership fix pass, a `~Copyable` global consume
twice and a diagnostic that would not have fired.
Verified: 519/519 unit tests, pre-deploy --static clean, distributions regenerated.
Reviewing the fix pass found one defect it had reintroduced and several claims it
could not have checked.
The confirmation fixes in testing-async.md replaced a non-waiting pattern with
`await api.fetch { ... }`. That compiles against a callback-taking call, but only
by warning `#UnnecessaryEffectMarker` — the `await` is a no-op and returns
immediately, so the confirmation still races the callback. The fix's own comment
claimed the call "must suspend until the callback has run", which is exactly what
it does not do for the API shape the pattern teaches. Both sites now bridge with
`withCheckedContinuation`, the form the sibling file test-failure-analyzer.md was
already using for the same rule — so the two files agree again. Verified: the
continuation form compiles against a callback-only API (exit 0), the `await` form
compiles only with the no-op warning.
Three claims checked against their sources rather than taken on report:
- `/testing/issue/severity-swift.enum` resolved correctly, and the accessibility
path's underscore-to-hyphen change is right.
- WWDC 2023-10269 and 2024-10206 both redirect; their replacements resolve.
- Xcode's own UI-test template puts `@MainActor` on the test method, so the
annotation ui-recording.md gained is Xcode's convention — but the block's
comment attributed it to the recorder, which the audit could not verify. The
comment now says what the annotation is for instead of where it came from.
Also checked and deliberately left: `await bgContext.perform { }` in axiom-data is
a genuine async overload (compiles clean, no no-op warning), so it is not the same
defect. A stray blank line inside the empty `defaultOptions` object was removed.
Verified: 518/518 unit tests, pre-deploy --static clean, distributions regenerated.
Second suite of the corpus audit. 8 files, 161 code blocks, ~447 API claims checked.
Blocks were compiled at the iOS 18 floor with the Developer-tree XCTest/Testing search
paths and, where the claim was behavioural, executed — `swift test` on the host and
`xcodebuild test` on booted iOS 27.2 simulators.
Two systemic misconceptions, each found independently in more than one file.
`confirmation` does not wait. It checks the count when the closure returns, so a
callback that fires after that is a hard failure, not a wait. testing-async.md taught it
as deterministic waiting and mapped XCTest's `wait(for:timeout:)` to it; the fix it
recommended converted a passing-but-vacuous test into a deterministically failing one.
test-failure-analyzer.md's two "✅ CORRECT" fixes failed 4/4 runs, and its Pattern 5
taught `confirmation(expectedCount: 0)` as proof a callback never fires — it is not: a
late confirm() is counted zero times, reported nowhere, and the test stays green.
A test plan's `userInterfaceStyle` does nothing. The app follows the simulator. Two files
published it as the way to test Dark Mode; a probe app printing its own colorScheme
reported the simulator's setting in every variant, and the JSON block would not load at
all until two missing keys were added. The deterministic route is device-level
`xcrun simctl ui <udid> appearance dark`. `XCUIDevice.shared.appearance` works but races
the launch — measured — so it is described as racy rather than recommended.
Also fixed: a published `.xctestplan` that could never load; a menu item that exists
nowhere in Xcode ("Debug → Record UI Automation"); `XCUIApplication.openURL`, which is not
the API; a fix that could not compile (`self is immutable`); `.timeLimit(.seconds(5))`,
which is explicitly unavailable; and `@Test` inside an XCTestCase subclass, which the
macro rejects.
One agent edited the generated copy of an inlined auditor instead of its agent source.
The drift gate caught it and the work was moved; the gate did its job.
Verified: 518/518 unit tests, pre-deploy --static clean, inlined-auditor and Cursor drift
checks current, all three generated distributions regenerated, and both suites recorded in
the out-of-repo ledger (corpus coverage 44 -> 60 files, 0 stale).
Reviewing the fix pass found three things the fixers' own probes did not.
concurrency-profiling.md's fix added `@concurrent func heavyComputation() async -> Int`
with a comment-only body. That is `error: missing return in global function expected to
return 'Int'` — the fix introduced a defect of the same class it was repairing. It now
returns a value.
The two files that qualified the NonisolatedNonsendingByDefault claim qualified it in
opposite directions: the discipline file said "on by default in new Xcode projects", the
router and the auditor said "off by default". Both are true and neither is complete —
Xcode's Base_ProjectSettings.xctemplate sets SWIFT_APPROACHABLE_CONCURRENCY = YES, so new
Xcode projects have it on, while the build setting's own default is NO and SwiftPM does not
enable it. All five sites now say that. The earlier note in this session calling the claim
unverifiable was wrong: it is checkable in the template's TemplateInfo.plist.
isolation-inheritance-diag.md still told the reader to reproduce the crash by driving Core
Data through `context.perform` from a background-spawned task, after the fix deleted the
section explaining that it no longer traps. Removed — a cutover the fix pass missed.
Verified: 518/518 unit tests, pre-deploy --static clean, inlined-auditor and Cursor drift
checks current.
First suite of the corpus audit. All 160 Swift blocks were compiled as probes at
the iOS 18 floor and every API claim checked against the 27.2 SDK interfaces and
swiftinterfaces. 35 findings across the 8 files: 21 defects (wrong as written),
4 stale (teaching a fix for a problem the SDK has since solved), 10 sub-floor.
Every file had at least one.
The worst was silent. assume-isolated.md recommends testing MainActor code with a
nonisolated `@Test` calling `MainActor.assumeIsolated`; that compiles clean and
traps at runtime, because Swift Testing does not run nonisolated synchronous tests
on the main thread. It takes down the whole test process with SIGTRAP, and no
compiler can warn about it — which is the argument for a harness that runs what it
checks rather than only compiling it.
Elsewhere of that class: Pattern 9's copy-paste SwiftData template returns
non-Sendable models across an actor boundary and cannot compile for any conforming
type; four ✅ blocks fail under `-swift-version 6` for the same missing `@MainActor`;
a gotcha table teaches that `case failed(Error)` is a compile error when `Error` has
been Sendable since Swift 5.5; and a documented debug env var is absent from every
runtime Apple ships.
Two failure modes worth naming, because neither is reachable by compiling code
blocks alone. Content that teaches a FIX for a problem the SDK already solved —
Core Data's `perform` already takes a sendable block, so the ❌ does not fail and
the "fix" is a no-op. And content that teaches a DIAGNOSTIC that no longer exists.
Gotcha tables and decision trees need the same scrutiny as the code.
One claim was wrong in the same direction in three files at once: that an async
function resumes on the caller's actor. True only under
NonisolatedNonsendingByDefault, which defaults to NO, so the auditor could report
a false CRITICAL. Qualified at every site, and in the agent source rather than in
its generated output — the inlined sub-skill is built from that source by
build-inlined-auditors, so editing the output alone would have tripped the drift
gate and been overwritten.
The suite is substantially correct elsewhere: the @concurrent and actor machinery,
the Sendable rules, the OS27 ProgressManager section and the crash signature table
all check out, several of them character-for-character.
Verified: 518/518 unit tests, pre-deploy --static clean, all six generators current,
and all 8 files recorded in the out-of-repo ledger (corpus 44 -> 52 verified).
My earlier rebuild (the privacy commit) dropped the stripping the committed
binaries had: they went from 3.9-8.8 MB to 9.0-9.9 MB. The Makefiles now pass
-ldflags "-s -w", which is what the hand-built binaries had before a Makefile
existed for all four tools. Sizes are 6.0-6.6 MB now — three of the four are
smaller than the versions they replace, and xclog is larger than its 3.9 MB
hand-built predecessor, which used an older toolchain. All four Go modules pass.
The restored sentence — "This agent writes code; it has no /axiom:audit form" — was
invisible while it lived in the frontmatter description, which every emitter
strips. In the body it is emitted, the Codex build annotates it as unresolvable,
and check 12o flags the resulting pointer. Not a check bug: Codex ships no
commands, so a bare /axiom:audit reference has no target to resolve. Reworded to
keep the hand-off ("use the iap-auditor agent, which /axiom:audit iap invokes")
and drop the dangling reference. Phase 1 clean.
Axiom-2fa kept the first sentence and moved the <example> blocks, but dropped
everything else the description carried, in all 42 agents — the closing prose
that said what the agent covers and, in three cases, who should get the prompt
instead:
- iap-implementation lost "This agent writes code; it has no /axiom:audit form.
To review existing IAP code instead, use /axiom:audit iap (the iap-auditor
agent)." The implementation agent has Write/Edit and the shipped trigger had
no exclusion, so review-shaped prompts named the same vocabulary.
- triage-analyzer lost "For a single crash file (.ips, MetricKit, .crash,
.xccrashpoint), use the crash-analyzer agent instead."
- swiftui-architecture-auditor lost "Complements (but is distinct from)
performance and navigation audits."
My own verification missed it because it compared bodies, and this content was
in the frontmatter. Each agent's dropped prose now lives in a `## Scope`
section, and a check confirms every tail sentence exists in its file.
Two router descriptions lost capabilities in the same rewrite and the restore
pass missed them: axiom-build's test-crash trigger ("a crash log needs
diagnosing, a test run crashes") — the capability ships in SKILL.md and
xcode-debugging.md, and axiom-testing routes it here — and axiom-shipping's
"age ratings", which the suite documents in four places and the deterministic
hook matches verbatim.
Found by an independent security review of the repo, not by a gate — the
leak-prevention hooks are filename-scoped and cannot see content classes.
- scripts/cursor/fixtures/cursor-3.17.8-hook-payloads.json embedded a real
session path (which encodes the maintainer's home directory) and a real
session UUID in seven fields.
- The committed .crash fixture kept the real app's Version and build stamp
(1.0.0 / 1000000000), the crash's Date/Time and Launch Time with the
device's UTC offset, and the full binary inventory of a framework whose name
the anonymizer deliberately hides (wavpack, ogg, FLAC, opus, vorbis, lame,
mpc, mpg123, sndfile, tta-cpp, Lottie) with their build UUIDs. The
anonymizer has no rule for any of those keys, which is why they survived;
editing them does not touch the fixture's fixed-point test because nothing
rewrites them.
- scripts/migrate-skill-namespace.sh hardcoded /Users/you/Projects/Axiom,
publishing the layout and making the script unusable anywhere else.
- Four shipped skill files used the maintainer's identity where the corpus
uses placeholders: /Users/you/... in sandbox-and-file-access.md,
~/charles-personal.p12 and "Apple Distribution: Charles Personal (ABC123)"
in code-signing.md, and an unpatterned device UDID in xctrace-ref.md.
- testflight-triage.md published measured production triage figures and a real
app-internal symbol (16 of 17 signatures, crashHandlerSymbol); the lesson
survives without the numbers or the symbol name.
- The three tool Makefiles built without -trimpath, so the maintainer's source
path was embedded in every shipped binary, and xclog had no Makefile at all —
its binary was hand-built with the absolute path in its debug info. All four
tools now build with -trimpath; strings over the four shipped binaries
reports zero /Users/you occurrences, down from xclog=1 and the three
others at their previous values.
Claude Code's always-on cost was 54,966 chars, 39,359 of it agent descriptions —
the same 42 agents Cursor and Codex carry for ~6,100, because both emitters
already truncate each description to its first sentence. The <example> dialogues
exist to teach triggering; the first sentence already carries the trigger, and
the dialogues now live in the body, which loads only when the agent runs.
Measured before landing — 169 prompts (each agent's own <example> user lines,
labelled with the agent that example names) classified against all 42
descriptions, two runs per condition:
full text 169/169, 169/169 (the examples contain their own answer, so
this level is an artifact, not a baseline)
first sentence 168/169, 166/169
The three deviations are two-way calls between plausible agents —
spm-conflict-resolver over build-fixer for "No such module after I updated
packages", test-debugger over build-fixer for "tests passed yesterday but now
fail", security-privacy-scanner over grdb-performance-auditor for "scan for SQL
injection in GRDB code". No cross-domain misroutes. The corpus cannot rule out a
larger effect on other model classes, and it is built from the removed examples,
so it is the hardest available test for the truncated form, not a field result.
Why the risk is bounded: the surface that changes is discretionary selection.
The skills carry 102 "Launch `<agent>` agent" directives covering all 42 agents,
and commands another 33, so designed flows choose their agent from skill text
either way — untouched here.
Always-on: claude-code 54,966 -> 22,059 chars (~18,322 -> ~7,353 tokens, -60%).
Ceiling ratcheted 56,000 -> 24,000.
Gates that had to move, with reasons:
- always-on-footprint.test.ts asserted the 6.4x Cursor/Claude Code gap. The gap
was the defect, so it now asserts near-parity; re-opening it fails the test.
- audit-parity's advertised-area and advertised-command parsers read the
frontmatter description only. The `Explicit command:` hints now live in the
body, so both scan the whole file — a ghost command promised in the body is
exactly as broken as one promised in the frontmatter, which is the check's
purpose. Two tests encoded the old frontmatter-only contract; they now assert
the new one, plus a new case proving a body-promised ghost is caught.
- Four agents (energy, memory, swift-performance, swiftui-performance) had lost
the vocabulary their audit area checks for; it is back in the trigger
sentence, which also routes on those words now. foundation-models and
spritekit gained theirs as well.
- `/axiom:audit all` carries "(Claude Code only)": Codex has no commands and the
emitter cannot map `all` to an area.
Note: 250 chars is Axiom's own emitter budget, not a platform cap. The Agent
Skills spec allows 1024; Claude Code documents 1536 for description +
when_to_use; Codex enforces 1024 and shortens long descriptions for its listing.
An independent review of the previous commit found that seven of the twelve
rewrites removed the only description surface for content their own suites still
ship — the same defect the rewrite existed to repair, reintroduced elsewhere.
- axiom-integration had dropped "timers" and "reminders"; timer-patterns.md and
eventkit.md own both, and axiom-performance routes four timer prompts here.
- axiom-swiftui had dropped "performance" and "architecture" to stop colliding
with other routers, but swiftui-performance.md and architecture.md are its own
children and its own text says "try axiom-swiftui first" for slow UI. Scoped
instead of dropped: "view-level performance, feature architecture".
- axiom-media had narrowed CarPlay to metadata; carplay-hig.md,
carplay-templates-ref.md and carplay-navigation-ref.md own app design,
entitlements, templates and navigation, and axiom-design routes that work here
by name.
- axiom-build had claimed TestFlight crash triage, which axiom-shipping owns
(its own table forwards "beta tester reported a crash" to that suite); it now
claims the local crash log it actually analyses.
- axiom-design restores auth-flow structure (app-composition.md owns the state
machine); axiom-shipping restores App Store Connect automation alongside the
accurate Xcode Cloud claim (asc-mcp.md).
- axiom-apple-docs loses its trailing mechanism clause, which told the model what
the skill does rather than when to load it.
- axiom-performance's platform anchor is "Apple-platform", not an enumeration:
its children carry watchOS and tvOS memory, energy and MetricKit content, and
"battery drains" is the canonical watchOS question.
Measured with the same description-only classification over 59 real and 25
synthetic prompts, before and after the whole change: SHOULD recall 16/17 ->
17/17, pointer rows routed 1/24 -> 0/24, false fires 2 rows (one unique prompt,
"Do we have a pop-triage skill?", which axiom-tools' own text claims to answer).
axiom-swiftui's share of picks falls 40% -> 35%; the deeper reduction the first
pass measured came from orphaning its two children and does not survive contact
with the suite's actual contents.
Nine defects in the 27 router descriptions, from the Axiom-65q.10 measurement of
the one invocation mechanism that had never been tested — the model's own choice
from the description list. Every harness is affected, including MCP, where
descriptions are the only lever.
- Crash reports had no description surface at all. /axiom:analyze-crash,
/axiom:triage, xcsym and the crash-analyzer and triage-analyzer agents ship, but
nothing said so: axiom-build now names crash logs and TestFlight crashes,
axiom-shipping names TestFlight/Sentry corpus triage.
- axiom-apple-docs fired on nothing. Its trigger was a superset of every other
router's and its Covers list duplicated five suites, so a maximal trigger with
no discriminating content was easy to ignore. It now triggers on needing
Apple's own documentation rather than on any Apple question.
- Four routers named no platform, so axiom-data's trigger literally covered "set
up a Postgres migration". iOS/macOS/visionOS anchors added to axiom-data,
axiom-networking, axiom-performance and axiom-concurrency.
- axiom-swiftui claimed "performance" and "architecture", colliding with two other
routers; it absorbed 40% of picks. Both claims dropped.
- axiom-media claimed the bare phrase "Now Playing" — also a screen name — so
layout work on a screen called Now Playing routed to the wrong suite. Scoped to
lock-screen and CarPlay metadata.
- axiom-design is scoped to visual and interaction decisions for an Apple app, and
no longer claims authentication flows.
- axiom-swift is narrowed off "any Swift edit".
- axiom-integration's 13-noun keyword list became the condition it stands for,
which is what skill-descriptions.md asks for.
- Xcode Cloud configuration claimed by axiom-shipping.
Listing text: 5,429 -> 5,317 chars. axiom-media (273) and axiom-shipping (252)
were past the 250-char point where the Codex variant truncates mid-sentence; both
now ship whole.