mirror of
https://github.com/CharlesWiltgen/Axiom.git
synced 2026-09-20 19:58:20 +08:00
4fec142381fe36ff35c949df5cf375b99077ba60
1553 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4fec142381 |
fix(gate): make pre-deploy compare manifest descriptions, not just presence
`claude-code.json`'s skills array is generated from each SKILL.md's frontmatter, but check 4 only verified that every manifest skill had a SKILL.md on disk — never that the description matched. The one assertion comparing the two texts lived in scripts/skill-listing.test.ts, which runs under `npm run test:unit` (what CI runs) but not under `npm test` (what a maintainer runs), and `node scripts/skill-listing.ts` reports character budgets only and exits 0 on drift. So editing a router's description — the most ordinary kind of change in this repo — left the manifest stale, and the `/axiom:ask` generated from it, through a green local gate and four consecutive red CI runs. Check 4 now compares the text and names the first drifted skill. Verified in both directions: it reports 26 manifest descriptions matching, fails with `[manifest-drift]` naming axiom-media when a description is injected, and passes again once that is reverted. Verified: npm test (static validation clean) and npm run test:unit (519/519). |
||
|
|
e469fa76c6 |
fix(manifest): regenerate the axiom-media listing after its description changed
`claude-code.json`'s skills array is generated from SKILL.md frontmatter, so the
router description corrected in
|
||
|
|
2ec48f7c72 |
fix(axiom-media): unblock a quoted Objective-C constant, and a search that could not match
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). |
||
|
|
574048c017 |
fix(axiom-media): requote the CarPlay passages taken from the superseded guide
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). |
||
|
|
3105b1118b |
fix(axiom-media): correct what reviewing the fixes found, and sweep the docs pages
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). |
||
|
|
19208d3a83 |
fix(axiom-media): verify the suite against the 27.2 SDK and fix what it disproves
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). |
||
|
|
a0a6c2e94f |
fix(axiom-swiftui): verify the suite against the 27.2 SDK and fix what it disproves
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. |
||
|
|
cf1ebc772c |
fix(axiom-data): verify the suite against the 27.2 SDK and fix what the toolchain disproves
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. |
||
|
|
a480497bf2 |
fix(axiom-swift): correct the tvOS storage phrasing in the router
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. |
||
|
|
92b05bfe5c |
fix(axiom-swift): review the fix pass — propagate the tvOS storage correction to the router
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. |
||
|
|
b56558e6ca |
fix(axiom-swift): verify the suite against the toolchain and fix 47 findings
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. |
||
|
|
03a84d3de8 |
fix(gate): scan the repo configuration too, and assert nothing tracked goes unread
The leak scan reads an enumeration — SURFACES plus ROOT_FILES — so any tracked file outside it is invisible, and an unread file reads as a clean one. Nine were: .gitignore, .gitattributes, .mise.toml, and .github/** (dependabot plus the three workflows). All clean today, which is the point: nothing would have caught it if they were not. This is the second time the enumeration has drifted — Axiom-77q9 fixed the first, 38 files under axiom-mcp — and both were found by hand rather than by the gate. .github is now a surface and the three dotfiles are root files, so the scan reads 1985 files instead of 1978. The workflow's paths filter gained the same four entries, since a change to a file the scan reads must still start the job — the CI-paths test enforces that pairing and failed until it did. The durable fix is the assertion rather than the four additions: a new test derives the tracked file list from git and fails if any file is in neither the scanned set nor SELF_EXEMPT, naming the file and where to declare it. Verified by deleting the .github surface and watching it fail with all four paths listed, then restoring. The third omission now fails in CI instead of waiting to be noticed. Verified: 518/518 unit tests, 15/15 leak-scan tests, pre-deploy --static clean. |
||
|
|
4257671cee |
fix(ci): skip the dev-state guard tests in a checkout that has no dev state
The Test Suite workflow has failed on every push since it was added. Three tests in scripts/methodology-leak.test.ts read `.claude/rules/skill-development.md` and `.claude/skills/preflight/skills/behavioral-testing.md` and die with ENOENT in CI, because `.claude/` is gitignored: those files exist on a maintainer's machine and nowhere else. Locally the suite is 518/518; in a fresh checkout it was 515/518. The tests themselves are sound — they guard a real invariant, that behavioral-test methodology stays out of the file the harness appends to every skill-file Read, so it cannot reach a GREEN arm and confound a behavioral test. The subjects are just local dev state, so the precondition is "this checkout has dev state" and the tests skip when it does not. They still run wherever the state exists, which is the only place the leak they guard against could actually occur. The second test deliberately gates on the presence of the RULES file rather than its own subject: deleting the canonical file while the rules file remains is the "fixed it by deleting the content" regression it exists to catch, and it must fail then, not skip. Verified in three checkouts: dev state present 3 pass / 0 skip; no dev state 3 skip / 0 fail; rules file present with the canonical file deleted 1 fail. Before the change, the first two were 3 fail and the third was 3 fail. The workflow did its job here — it is the first thing to run this suite outside a maintainer's machine, and it found a suite that could not pass outside one. |
||
|
|
89e05c116b |
fix(axiom-testing): review the fix pass — an await that does not await, and three unverified claims
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.
|
||
|
|
5c804a38d2 |
fix(axiom-testing): verify the suite against the toolchain and fix 57 findings
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).
|
||
|
|
c6fa657e3f |
fix(axiom-concurrency): review the fix pass — a compile break, a self-contradiction, a stale bullet
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. |
||
|
|
7a15dcbbfb |
fix(axiom-concurrency): verify every API claim against the SDK and fix the 35 findings
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). |
||
|
|
93f793709f |
fix(tools): replace captured identifiers in test fixtures with synthetic ones
The warn tier's last 8 findings were all real values sitting in fixtures: three
Apple OS binary UUIDs (libsystem_kernel.dylib, /usr/bin/yes, dyld) from a real
cpuprofile trace, and a display UUID captured from `devicectl device appResize
set`. None was sensitive, and the obvious response was to exempt them — which
would have been the wrong one. An exemption is permanent: it lives in the scanner
forever, and each one narrows what the gate can still catch.
The values were also inert. cmd_resize_test.go asserts the parsed "Actual size"
field and never reads the display id; the cpuprofile assertions need only the
fixture and the expectation to agree.
So the fixtures carry synthetic UUIDs now, and the scanner's own test assembles
its unpatterned control values from parts rather than writing literals. That last
part matters because the test file is shipped content like any other — a literal
there is a value the gate has to carry forever. Same move
|
||
|
|
180000ce24 |
fix(tools): remove a real hardware UUID from the xcprof fixtures
tools/xcprof/testdata/toc.xml and network-toc.xml carried the maintainer's IOPlatformUUID in the trace's <device> node, next to model="Mac Studio" and os-version="26.5 (25F71)". Verified against `ioreg -d2 -c IOPlatformExpertDevice`, which returns the same value. It entered in |
||
|
|
980ae18486 |
fix(gate): report a scanner failure as a failure, and make the block-scalar guard able to fire
Two P3 guards in the content gate could not do the job they were written for. `pre-commit-axiom.sh` captured the scanner's output and then filtered it to `^ ✗|error(s)`. When the scanner crashed rather than reported, that filter discarded its entire message and the hook still asserted "private data in shipped content" — a confident diagnosis the run had produced no evidence for. The hook now branches on whether a `✗` line exists: findings are printed and the failure says so, and their absence means the scanner failed, which gets its own wording and the raw output. Verified in a sandbox against a scanner that throws and one that reports. `always-on-footprint.test.ts` asserted the absence of a block scalar against `String(matter(file).data.description).trim()`. gray-matter resolves `description: |` to its content, so that assertion could only fire on a description whose literal text was `|` — the byte count the test sums changes for exactly the case it was meant to catch. The shape is now asserted against the frontmatter region of the file text, and fires on `|` and `>-` while leaving a quoted "|" alone. Also drops an SC2181 in the same hook. pre-deploy check 11 shellchecks only the plugin's own hooks/ directory, so scripts/git-hooks/ — this gate's machinery — has never been linted. Verified: 518/518 unit tests, 14/14 installer tests, shellcheck clean, and both hook branches exercised end to end. |
||
|
|
aa1d1ddd08 |
fix(gate): cover what the scan reads in the CI paths filter, and make the hook installer idempotent
The test-suite workflow's `paths` filter listed nine prefixes while its two steps read considerably more. `node scripts/leak-scan.ts` walks every SURFACES entry plus ROOT_FILES — `.cursor-plugin`, `.agents`, `axiom-codex`, `axiom-cursor`, `axiom-mcp` and the root release files among them — and the unit suite covers `axiom-pi` and `axiom-mcp`. A PR that added a home path to README.md or a real UUID to `axiom-codex` therefore started no job at all, which is exactly the case this workflow exists to backstop on a fresh clone or a `--no-verify` commit. The filter now lists all twenty entries per event, and a test derives the coverage requirement from the scanner's own SURFACES and ROOT_FILES so the two cannot drift apart again. `install-git-hooks.sh` grew the hook by one line on every run: the strip removed the block but left the separator blank line on both sides of it, and the insert added one back. The block now contributes no leading blank and the strip consumes the trailing one, so a re-install leaves the file byte-identical. Verified: 518/518 unit tests, 14/14 installer tests, leak scan 0 errors across 1978 shipped files. |
||
|
|
34d174869c |
fix(gate): close the content gate's coverage and reporting holes
Five defects, all in the gate added on 2026-09-15, found by two independent review passes and then traced to root causes. The installer appended its block to .git/hooks/pre-commit, so a foreign block that terminates the script left the whole gate unreachable while the installer reported success. This repo's own hook is that case: the beads block carries `if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi`. It now strips any existing block and re-inserts after the shebang, which also MOVES a block an older revision left in the wrong place — the live hook was reordered by running it. SURFACES replaced the tracked `axiom-mcp` entry with `axiom-mcp/dist`, leaving 38 tracked files — src/, package.json, and the npm-published README and LICENSE — in no surface. Both entries are needed; both are present now, and the scan sees 1,977 files against 1,939 before. Both warn-tier suppressions were dead. The issue-id guard tested m[0], which carries the `issue_id": "` prefix, against an anchored id pattern: it could never match, so it warned on the ACME-*/ASC-* placeholders it exists to suppress. The UUID allowlist missed the RFC 4122 example and every doubled-character shape. Warnings fall from 89 to 16, and a test now asserts a suppressed value stays quiet — the one thing the suite never checked. Check 12s counted its warnings and printed none while telling the reader to eyeball findings it never showed. They go through warn() now, which the Phase 1 block renders. The CLI derived its root from new URL(import.meta.url).pathname, which keeps percent-encoding: from a checkout path containing a space every surface walked to nothing and the guard then blocked every commit, naming the wrong cause. Verified in a worktree at such a path — old idiom exit 1, new idiom exit 0. A lint keeps the lossy idiom from returning anywhere in scripts/. .github/workflows/test-suite.yml runs the unit suite and the content scan on pull requests and on main. Neither had ever run off a maintainer's machine. It deliberately omits `npm run test`: that gate's first check shells out to `claude plugin validate` and treats the CLI being absent as a failure. Verified: 515/515 unit tests, Phase 1 static PASSED, leak scan 0 errors / 16 warnings over 1,977 files. The remaining 16 are real dylib and profile UUIDs in tools/*/testdata, listed in the summary output for a decision on allowlisting. |
||
|
|
2abd614ba1 |
docs(hooks): drop the stale Codex no-prompt-routing claim
The Harness Support intro said Codex has "no per-prompt routing hook in the same form", three lines above a table that marks per-prompt routing supported on Codex. The clause predated the port of the hooks to the Codex variant: the generated axiom-codex/hooks/hooks.json binds UserPromptSubmit with no matcher (Codex rejects one on that event), and user-prompt-submit.py returns hookSpecificOutput.additionalContext, the context-injecting shape a routing nudge needs. Removed the clause so the prose agrees with the table and with what ships. The page already states the real caveat elsewhere — Codex needs features.hooks = true, and a skills-only install gets no hooks at all. Verified: docs build clean, npm run test:unit 498/498, Phase 1 static PASSED. |
||
|
|
a05602455c |
fix(leak-scan): silence git's stderr for files that ship from disk
Asking for the staged blob of an untracked-but-published file is an expected miss; printing 'exists on disk, but not in the index' forty times inside check 12s buries the result line. |
||
|
|
6bfbfd766c |
fix(leak-scan): close the holes an independent review found
Sixteen findings across two reviews, all in the guard and the fixes it prompted. The guard: - The pre-commit step resolved `tsx` through `npx`, and tsx is not a dependency: on a fresh clone or offline, the download failure took the failure branch and blocked the commit with "private data in shipped content" — a wrong and alarming diagnosis. It runs under plain node now (Node 24 strips types), like every other TypeScript entry point here. - A failing run printed `tail -20`, which is trailing warnings plus the summary — the `✗ path:line` naming the offender scrolled off. It greps for the error lines. - Files were listed from the index and read from the working tree, so staging a leaking revision and restoring the clean file on disk passed the scan. It reads the staged blob, and a staged-then-deleted file no longer throws ENOENT. - Several tracked, shipping surfaces were never scanned: `.cursor-plugin/`, `.agents/`, the whole `axiom-pi/` package, the submission Markdown at the root, and `package-lock.json`. The npm bundle needed the opposite treatment — axiom-mcp/package.json publishes `dist/`, which is gitignored except two JSON files, so that surface is read from disk. - CHANGELOG.md was in ROOT_FILES but is gitignored, so the entry could only fire on the fallback path: the scan reported clean while the file still named the app. Root files are read from disk now, and that is exactly what it found — a third mention the earlier cleanup missed, and which the close note on Axiom-1z8m wrongly claimed was fixed. Corrected here. - The uuid rule was uppercase-only (Claude Code session paths are lowercase), the tracker rule's exclusion list sat where it could not apply (checked in code now), and printable runs in binaries were collected at 16+ characters, long enough to miss short values. - A scan that finds almost nothing now reports a broken scan instead of clean (floor on the file count, in both the CLI and check 12s). - The hook itself was untracked, so the guard vanished on a fresh clone. It lives in scripts/git-hooks/pre-commit-axiom.sh and is spliced in by scripts/install-git-hooks.sh, idempotently, leaving the beads block alone. The fixtures the earlier round was supposed to have cleaned: - The two xccrashpoint copies of the crash still carried the framework's full codec inventory and its build UUIDs, and the copy that was edited kept the same names in the path column. Both files and that column are neutralised. - The real crash instant survived in the two fixture file names while the header said 2026-01-01; the names now match the header, and nothing asserts them. - crash_text_test.go pins that the dedup-symbol frame resolves its image, so the case cannot pass while exercising the unknown-image path. Scan: 0 errors, 89 warnings across 1937 shipped files. Unit 498/0; xcsym and xcui pass, including the anonymizer fixed-point test against the edited fixtures. |
||
|
|
9a937f573b |
build(tools): strip the shipped binaries again
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. |
||
|
|
e6f267cebb |
test(leak-scan): inject the rule set, so no real deny-list value lives in a test
Groundwork for scrubbing the repository's history: a test that asserts on private values puts those values back into the tree, where any history rewrite has to touch them. The engine now takes its rules as a parameter, and the tests exercise it with their own synthetic set. The shipped list gets a structural test instead — rule ids and the five error classes, not values. |
||
|
|
8a696061f5 |
feat(gate): scan shipped content for private data (check 12s + pre-commit step)
Axiom-1z8m. The identifier class leaked four separate times — skill examples, the xcsym/xcui fixtures, a Cursor hook fixture carrying a real session path and session UUID, and all four bundled binaries embedding the maintainer's source layout — and no gate saw any of it, because the pre-commit hooks match file names and directories only. scripts/leak-scan.ts scans what ships, where "ships" means tracked: the plugin, the generated Codex/Cursor variants, the MCP bundle, docs, and the tool and script trees that carry fixtures. Files are read as UTF-8; anything with a NUL in its first block is scanned through its printable runs, which is how a source path embedded in a binary gets caught by the same rules as prose. Rules, each with a test: project names, personal home paths (including Claude Code's encoded -Users-<name>- form), session temp paths, and timestamp-shaped build stamps are errors; unpatterned UUIDs and quoted tracker ids warn, and obviously synthetic values (AAAA…, 1A2B…, ACME-*, /Users/you, REDACTED) are left alone so the warning tier stays worth reading. One allow entry exists, for the Cursor fixture, whose whole purpose is to be shaped like a real session path. Wiring: check 12s runs inside pre-deploy, and the pre-commit hook runs the scan on every commit regardless of staged paths — the class has come through tools/, fixtures and binaries, so staged-path gating cannot cover it. tools/ also joins the hook's full-validation trigger set. Proof it can fail: planting "ExampleApp" in README.md makes the scan exit 1 with the file and line, and reverting restores it. It also found two real leaks on first run: the xccrashpoint fixtures still carried the real app version and crash timestamps (the earlier fix covered only the apple_crash fixture), and two public CHANGELOG entries named the app while describing past scrubs. |
||
|
|
a776996e4c |
fix(agents): keep iap-implementation's hand-off without a dangling command reference
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.
|
||
|
|
4e8555b3d7 |
chore: rebuild the Codex, Cursor and MCP copies
Regenerated from the restored agent bodies and the two router descriptions. |
||
|
|
dfcae86e07 |
test: derive expectations from parsers and data, not from copies of the reader
- always-on-footprint.test.ts computed the expected skill-listing size with a regex that mirrored the reader's own inline rule, so it agreed with the reader even when both were wrong: a quoted description kept its quotes, a continuation line was dropped, and a `description:` with an indented continuation failed with a misleading message. It now parses with gray-matter, as the sibling listing test does for the same reason. - crash_text_test.go's dedup case named its frame image "SomeApp" while the images slice it is passed holds "App", so UUID lookup missed and the case exercised the unknown-image path instead of the one it documents. - cmd_triage_test.go's comment still promised "huge user count" over data that had become users:9 events:12. The contrast is restored with invented values (1200/4500) rather than the real figures. |
||
|
|
fdd66c7a34 |
fix(agents): restore the description text the truncation deleted
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.
|
||
|
|
7e9facd7dc |
fix(privacy): remove the personal and production data still shipping
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. |
||
|
|
a2827fa449 |
test(footprint): guard the inline skill-description path
Every skill writes `description: Use when …` inline; every agent writes a `|` block scalar. The reader handles both, but the test guarded only the block form — so the shape the skills actually use was untested, and an inline-blind reader scores 27 descriptions at a handful of chars and reports the listing as free. That silent-zero class bit three times on 2026-09-15: run.py located the hook via HERE.parent.parent and printed 0/17 recall with 0% false positives after a directory move; an ad-hoc crash-triage check read only block scalars and reported zero hits against 27 inline descriptions; and this test could not have caught either. The expectation is computed from the files rather than from the reader, with a floor on the sample count so the guard cannot become vacuous, and an assertion that a future block-scalar skill description extends the test instead of silently passing it. |
||
|
|
888fd0a566 |
perf(context): ship agent descriptions as their trigger sentence
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.
|
||
|
|
88a0fc4694 |
chore(tools): replace real app data in xcsym/xcui fixtures with placeholders
The xcsym and xcui test fixtures carried data from a real project: the app name in sample crash reports, a live Sentry issue ID (APP-3V) with its real impact counts, and a dated incident reference in a comment. Axiom is a public repository; a private app's crash telemetry has no business in it. Placeholders only — "SomeApp [14250]", "APP-3V", users:9 events:12, and the incident comment drops the app name. Every execution path is unchanged: the anonymizer's bracket/pid handling, the header-line extraction, the dedup symbol classification, and the triage noise-flagging all still exercise the same shapes. The impact numbers in normalized_test.go moved with the assertion that checks them. Note: this removes the data from the current tree, not from git history. |
||
|
|
240fb500cf |
chore: re-sync manifests and rebuild the Codex, Cursor and MCP copies
Generated from the corrected descriptions; claude-code.json and /axiom:ask carry the text the harnesses actually list. |
||
|
|
40cf4f4028 |
test(skill-listing): derive the expectation with gray-matter, not a regex
The assertion's expectation re-implemented the loader's own parse rule, so it compared the module against a copy of itself and could not catch the loader mis-reading a shape it accepts: a quoted description keeps its quotes and a plain multi-line scalar loses its continuation, and both passed. gray-matter (already a devDependency) returns the frontmatter's meaning instead. The manifest-vs-disk guard for this file remains the sibling test, which fails when the listing comes from claude-code.json because axiom-tools is deliberately absent there. |
||
|
|
89b3ec5e9c |
fix(skills): restore the capabilities the description rewrite orphaned
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. |
||
|
|
ebda2140a0 |
chore: re-sync manifests and rebuild the Codex, Cursor and MCP copies
Generated from the descriptions above; claude-code.json's skills array and /axiom:ask carry the same text the harnesses list. |
||
|
|
4d688af290 |
test(skill-listing): check the shipped listing against frontmatter, not a prefix
The test is named "carries the frontmatter description verbatim" but asserted a hardcoded prefix of one description, so it failed on every edit to that text without testing its own claim. It now reads axiom-shipping's SKILL.md and requires exact equality with the shipped listing entry — the same guard against the manifest-vs-disk defect it was written for, and immune to description edits. |
||
|
|
75c5c98a51 |
fix(skills): repair nine measured router-description defects
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. |
||
|
|
8cdc3e7919 |
chore: rebuild the Codex, Cursor and MCP copies for the 27.0 restamp
Generated from the skill files above; the Cursor inventory hash list moves with them. |
||
|
|
32de94bd2c |
fix(docs): DataDetector.MatchType has been available from 26 on every platform
The page scoped MatchType to iOS/macOS/watchOS/visionOS 27 and excluded tvOS. DataDetection carries @available(iOS 26.0, macOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *): all five platforms since 26. Only the SwiftUI .dataDetection(_:options:) modifier this bullet sits beside is 27-only, and only on iOS/watchOS/visionOS. |
||
|
|
7962933c0a |
docs: restamp 27.0 RC wording on the MCP reference page
Mirrors the skill change: the 54-tool verification is described as reproduced on the shipped 27.0 SDK, not on the release candidate. |
||
|
|
15693b4859 |
fix(skills): restamp 27.0 RC wording to the shipped SDK
Xcode 27.0 released as build 27A266a — the same build the release-candidate sweep
probed, with the iOS SDK at 24A430 — so wording that called it "the 27.0 RC" now
reads as pre-release in guidance describing what shipped.
Restamped only where RC stood in for the release ("verified on the 27.0 RC", "as
of the Xcode 27.0 RC SDK", "still gone in the Xcode 27.0 RC"). Beta-by-beta
history and every build string are kept: both stay accurate for readers on older
Xcodes.
Three lines needed more than a rename, after re-checking each against the 27.0
SDK. The Foundation Models adapters' "no replacement" claim drops its "(beta 1)"
provenance — Adapter carries deprecated 26.4 / obsoleted 27.0 with no renamed: or
message: hint, and LanguageModelExecutor ships as the pivot. The xcode-mcp tool-set
sentence names the release instead of a bare version sitting next to "beta 6".
Tap-to-pay keeps its provenance hedge, now scoped to the shipped SDK.
|
||
|
|
02b8cea5c2 |
chore(axiom-pi): build the parity probe inside the try/finally
A setup failure (or a hard kill) would otherwise leave axiom-parity-probe-<pid>.swift in the shared temp root — the junk class this suite exists to guard against, and now harmless to the detector but still litter. |
||
|
|
f7b891d9d7 |
fix(axiom-performance,hooks): restore visionOS availability; harden the temp-root guard
Corrects two things the earlier commits in this area got wrong, and closes the false positive they left open. CrashReportExtension visionOS availability. |
||
|
|
0fbb56821a |
fix(axiom-pi): port the temp-root fix, add a Python/TypeScript parity gate
axiom-pi/src/session.ts is a hand-maintained port of project_detect.py and had the same defect the Python fix just closed: a marker in the shared temp root made every cwd beneath it read as an Apple project, so Pi injected Axiom context in non-Apple workspaces. Checked against the exported isAppleProject before the change: temp dir true, temp root true. - port the temp-root neutralization (TEMP_ROOTS Record + computed realpath set, guard in the upward walk, temp root as a vacuous scan root) - mirror the three regression tests from project_detect_test.py - add a cross-implementation parity gate: one fixture matrix (plain dir, marker at cwd, in an ancestor, above a git root; .swiftpm home; visible .swiftpm package; project inside the temp root; plain temp dir; temp root itself; missing path; oversized tree) run through both implementations, failing on any mismatch. It rides the axiom-pi suite, which the full pre-deploy runs. |
||
|
|
ba04043bf8 |
fix(hooks): stop reading a system temp root as an Apple project marker
Both cursor adapter contract tests failed on main: they assert that a temp workspace is not an Apple project, and the detector said it was. Root cause is not the tests and not the adapter — the upward walk found an Apple marker sitting in the shared temp root itself ($TMPDIR/plan-test.swift, left by an unrelated tool), so every cwd beneath $TMPDIR inherited it. Same class as GH #52's ~/.swiftpm: tool state, not project evidence. - neutralize the temp root in the upward marker walk ($TMPDIR plus /tmp, /var/tmp, /private/tmp, abspath and realpath forms) - treat the temp root as a vacuous scan root, so containment there never falls through to a whole-tree scan - revert the failing tests to green with three new detector tests: a marker in the temp root is not evidence, the temp root is not a project, and a project that genuinely lives inside a temp dir is STILL detected (over-correction guard) Regenerated axiom-codex/ and axiom-cursor/ mirrors. |