Files
zeekay aa258b0988 Add the iOS lane: hanzo-templates had zero of them
The catalogue shipped 71 web templates and one EMPTY `mobile` repo, so
"build an app" had no starting point on the platform people actually
ship to. This is the iOS lane — Expo/React Native and Flutter for
cross-platform, SwiftUI for native.

The constraint that shaped every file here: an iOS archive needs macOS +
Xcode + a signing identity, and our arc fleet has none. hanzoai has 519
registered runners and every one reports `os: linux`; luxfi has 151, same
story; zooai has none. The only macOS builds in the org today
(hanzoai/world build-desktop.yml) run on GitHub-HOSTED macos-14, which is
exactly what the house CI rule says not to do.

So `hanzo.yml` declares only what a Linux arc runner can genuinely
execute — typecheck + web bundle for Expo, analyze + test + web for
Flutter, `swiftc -parse` for SwiftUI — and the macOS archive lives in a
separate `workflow_dispatch`-only `ios.yml`. A job pinned to a label no
runner advertises would sit queued forever if it fired on push; parking
it is honest, a permanently-yellow check is not. The README of every
template states the gap and the one command that closes it.

Same reasoning on the demos. Expo and Flutter both have a real web
target, so `<slug>.hanzo.app` serves the SAME source the simulator runs.
SwiftUI has no web target, so those two templates ship with no demo link
rather than a screenshot pretending to be one.

Upstreams are permissive only and recorded per template: expo/expo
templates (MIT), flutter/samples (BSD-3-Clause), XcodeGen (MIT).

Second measured gap, found while wiring this up: `hanzo-templates` is not in
arcd's `orgs:` list either (hanzoai, luxfi, zooai, parsdao, zenlm), so the
Linux jobs would queue with no runner too. Both gaps are one installer
re-run, no code change; both are spelled out in every README rather than
left to be discovered on the first red build.

Third gap, found by probing rather than assuming, and FIXED here: every
run in this org died as `startup_failure` with no logs and no annotation.
A bare `runs-on: [self-hosted, linux]` probe queued fine while the same
job importing hanzoai/ci failed identically at @v1 and at a pinned SHA —
so it was never the tag. The org defaulted GITHUB_TOKEN to `read`, and
the reusable declares `permissions: packages: write`; a caller cannot
exceed the org maximum, so GitHub kills the run before creating a job.
hanzo-templates now defaults to `write` like hanzoai/luxfi/zooai, and
runs reach `queued` — the honest state, waiting on gap 2.
2026-07-27 23:25:25 -07:00

28 lines
1.8 KiB
Dart

/// Local seed data. Swap `items` for a fetch against your own /v1 API — the
/// widgets only depend on the Item shape, not on where it came from.
class Item {
const Item(this.id, this.title, this.tag, this.blurb, this.body);
final String id, title, tag, blurb, body;
}
const items = <Item>[
Item('widgets', 'Everything is a widget', 'framework',
'Layout, gesture, animation and theme are all the same primitive.',
'A Flutter UI is a tree of immutable widget descriptions that the framework diffs into a mutable element tree, then into a render tree. You describe the frame you want; the framework works out the minimum it has to repaint.'),
Item('skia', 'Pixels are ours, not the platform\'s', 'impeller',
'Impeller draws every pixel, so iOS and Android look identical.',
'Because Flutter ships its own renderer instead of wrapping UIKit, a design lands byte-for-byte on both platforms. The cost is that platform widgets are imitated rather than used — the Cupertino library exists for when you want the iOS look.'),
Item('hot', 'Sub-second hot reload', 'tooling',
'State survives the reload, so you iterate inside the screen you are on.',
'The Dart VM patches classes in place and rebuilds the widget tree without restarting the app. Deep in a five-step form, you change a padding and see it without re-entering the form.'),
Item('aot', 'AOT-compiled for release', 'dart',
'Debug builds JIT; release builds compile to native ARM.',
'flutter build ipa produces machine code, not a bytecode interpreter. That is also why a release build needs the platform toolchain — for iOS, Xcode on macOS. See the README.'),
];
Item? byId(String id) => items.where((i) => i.id == id).firstOrNull;
extension<T> on Iterable<T> {
T? get firstOrNull => isEmpty ? null : first;
}