mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-15 09:25:28 +02:00
Merge origin/main (v1.60.1.0) into garrytan/gstack-fix-wave
Semantic reconciliation with the parallel time-attack wave (#2264):
- careful: adopt main's anchored full-command whitelist (stricter — also
catches comment-hiding), re-apply this wave's two hardenings on top
(capital -[rR] in the flag cluster; exclude `(` and backtick from safe
targets so $()/backtick substitution cannot ride the whitelist). Union
of both waves' test batteries passes (main's test.each incl. comment
case + this wave's substitution/capital-R/FP-pin cases).
- one-way-doors: main landed the singular noun unification (a2a447a1);
keep this wave's superset (plural s? + --summary-stdin runtime wiring).
- gbrain-local-status: union of states — main's engine-locked (#2194,
exit 124 PGLite lock) + this wave's thin-client (#2051). --is-ok keeps
main's intent (engine-locked = STOP) and this wave's (thin-client =
usable). Test harness unions both fake behaviors.
- sync-gbrain/setup-gbrain tmpls: both Step 1.5 branches kept; generated
SKILL.md resolved via bun run gen:skill-docs (never hand-edited).
- VERSION/package.json -> 1.61.0.0 per bin/gstack-next-version (main took
1.60.1.0; PR #2470 claims 1.60.2.0). CHANGELOG: wave entry renumbered
1.61.0.0 on top of main's 1.60.1.0; careful/#2024 bullets updated to
describe the delta vs current main. TODOS: union.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+28
-23
@@ -806,49 +806,53 @@ After `/ios-qa` is installed in an app, the user may:
|
||||
|
||||
1. Add new `@Observable` classes or properties that need accessor coverage.
|
||||
2. Upgrade gstack to a newer version with hardening fixes.
|
||||
3. Move the `@Snapshotable` marker to a different field.
|
||||
3. Move the `// @Snapshotable` generator marker comment to a different field.
|
||||
|
||||
This skill regenerates the relevant artifacts in place.
|
||||
|
||||
**Templates live in upstream gstack.** This skill resolves them from
|
||||
`~/.claude/skills/gstack/ios-qa/templates/` (or the worktree's
|
||||
`ios-qa/templates/` when developing gstack itself). The fork's HTTP-fetch
|
||||
pattern is gone.
|
||||
**Templates live in upstream gstack.** The installed
|
||||
`gstack-ios-qa-regen` launcher resolves its own gstack root and copies only
|
||||
the supported bridge files from `ios-qa/templates/`. The fork's HTTP-fetch
|
||||
and wildcard-copy patterns are gone.
|
||||
|
||||
## Phase 1: Detect installed version
|
||||
|
||||
1. Read `<app>/DebugBridgeGenerated/.gstack-version` (written by /ios-qa
|
||||
during install). If missing, treat the install as "unknown old version".
|
||||
2. Read upstream version from `$GSTACK_HOME/ios-qa/.gstack-version` (or the
|
||||
value baked into the installed gstack binary).
|
||||
2. Read upstream version from `$GSTACK_ROOT/VERSION`.
|
||||
3. If versions match AND no new `@Observable` classes were added, exit
|
||||
early with "already up to date".
|
||||
|
||||
## Phase 2: Regenerate codegen output
|
||||
|
||||
Run `gstack-ios-qa-regen` (or the underlying SwiftPM tool directly):
|
||||
Run the deterministic regenerator once. `--app-source` is the directory the
|
||||
accessor scanner should inspect; `--bridge-dir` is the local Swift package
|
||||
that the app links in Debug builds:
|
||||
|
||||
```bash
|
||||
swift run --package-path "$GSTACK_HOME/ios-qa/scripts/gen-accessors-tool" \
|
||||
gen-accessors --input "$APP_SOURCE_DIR" --output "$APP_SOURCE_DIR/DebugBridgeGenerated"
|
||||
~/.claude/skills/gstack/bin/gstack-ios-qa-regen \
|
||||
--app-source "$APP_SOURCE_DIR" \
|
||||
--bridge-dir "$APP_SOURCE_DIR/DebugBridge"
|
||||
```
|
||||
|
||||
The command removes only the known obsolete generated files from the former
|
||||
flat `DebugBridgeGenerated/` layout before emitting the current accessor.
|
||||
Generation accepts file-scope observable classes and JSON-native scalar,
|
||||
array, String-keyed dictionary, and Optional field types. It rejects custom
|
||||
types, implicitly unwrapped Optionals, nested observable classes, and duplicate
|
||||
snapshot keys before writing a completion marker.
|
||||
|
||||
The composite-hash cache key handles whether anything actually needs
|
||||
regenerating; if Swift version, generator git rev, lockfile, source content,
|
||||
and platform triple all match the cache, this is a ~50ms no-op.
|
||||
|
||||
## Phase 3: Update templated Swift files in place
|
||||
## Phase 3: Review the generated diff
|
||||
|
||||
For each file that comes from `ios-qa/templates/*.swift.template`:
|
||||
|
||||
1. Read the current installed file at
|
||||
`<app>/DebugBridgeGenerated/<Name>.swift`.
|
||||
2. Read the upstream template at
|
||||
`$GSTACK_HOME/ios-qa/templates/<Name>.swift.template`.
|
||||
3. If the installed file has a `// GSTACK-EDIT-LINE` marker, fold the user's
|
||||
edits forward.
|
||||
4. Otherwise, replace the file outright with the new template (after
|
||||
AskUserQuestion if the diff is non-trivial).
|
||||
1. Review changes under `<app>/DebugBridge/` and
|
||||
`<app>/DebugBridgeGenerated/StateAccessor.swift`.
|
||||
2. Confirm the command did not modify the app's handwritten Swift files.
|
||||
3. Keep app-specific wiring in the app target; canonical bridge package files
|
||||
are regenerated from upstream and should not be hand-edited.
|
||||
|
||||
## Phase 4: Verify
|
||||
|
||||
@@ -862,5 +866,6 @@ For each file that comes from `ios-qa/templates/*.swift.template`:
|
||||
| Symptom | Action |
|
||||
|---|---|
|
||||
| Swift compile fails after regen | Revert via `git restore` + AskUserQuestion: surface the compile error |
|
||||
| Schema hash unchanged after adding new @Observable | The new class isn't marked `@Snapshotable` — the codegen excludes it correctly. If the user wanted it snapshotted, add the wrapper. |
|
||||
| `--input` source dir contains test fixtures | gen-accessors scans the input dir recursively; exclude test/ via `--exclude` |
|
||||
| Codegen reports an invalid marked declaration | Use a file-scope observable class and a writable instance `var` with an explicit JSON-native type, internal/public setter, and a key unique across models; otherwise remove the `// @Snapshotable` marker. |
|
||||
| Schema hash unchanged after adding new @Observable | No field has the standalone `// @Snapshotable` marker comment — codegen excludes unmarked state correctly. Add the comment immediately above each field that should be snapshotted. |
|
||||
| Scanner sees generated bridge sources | Pass the narrow app source directory; the regenerator automatically excludes `DebugBridgeGenerated` and `StateAccessor.swift`. |
|
||||
|
||||
+28
-23
@@ -35,49 +35,53 @@ After `/ios-qa` is installed in an app, the user may:
|
||||
|
||||
1. Add new `@Observable` classes or properties that need accessor coverage.
|
||||
2. Upgrade gstack to a newer version with hardening fixes.
|
||||
3. Move the `@Snapshotable` marker to a different field.
|
||||
3. Move the `// @Snapshotable` generator marker comment to a different field.
|
||||
|
||||
This skill regenerates the relevant artifacts in place.
|
||||
|
||||
**Templates live in upstream gstack.** This skill resolves them from
|
||||
`~/.claude/skills/gstack/ios-qa/templates/` (or the worktree's
|
||||
`ios-qa/templates/` when developing gstack itself). The fork's HTTP-fetch
|
||||
pattern is gone.
|
||||
**Templates live in upstream gstack.** The installed
|
||||
`gstack-ios-qa-regen` launcher resolves its own gstack root and copies only
|
||||
the supported bridge files from `ios-qa/templates/`. The fork's HTTP-fetch
|
||||
and wildcard-copy patterns are gone.
|
||||
|
||||
## Phase 1: Detect installed version
|
||||
|
||||
1. Read `<app>/DebugBridgeGenerated/.gstack-version` (written by /ios-qa
|
||||
during install). If missing, treat the install as "unknown old version".
|
||||
2. Read upstream version from `$GSTACK_HOME/ios-qa/.gstack-version` (or the
|
||||
value baked into the installed gstack binary).
|
||||
2. Read upstream version from `$GSTACK_ROOT/VERSION`.
|
||||
3. If versions match AND no new `@Observable` classes were added, exit
|
||||
early with "already up to date".
|
||||
|
||||
## Phase 2: Regenerate codegen output
|
||||
|
||||
Run `gstack-ios-qa-regen` (or the underlying SwiftPM tool directly):
|
||||
Run the deterministic regenerator once. `--app-source` is the directory the
|
||||
accessor scanner should inspect; `--bridge-dir` is the local Swift package
|
||||
that the app links in Debug builds:
|
||||
|
||||
```bash
|
||||
swift run --package-path "$GSTACK_HOME/ios-qa/scripts/gen-accessors-tool" \
|
||||
gen-accessors --input "$APP_SOURCE_DIR" --output "$APP_SOURCE_DIR/DebugBridgeGenerated"
|
||||
~/.claude/skills/gstack/bin/gstack-ios-qa-regen \
|
||||
--app-source "$APP_SOURCE_DIR" \
|
||||
--bridge-dir "$APP_SOURCE_DIR/DebugBridge"
|
||||
```
|
||||
|
||||
The command removes only the known obsolete generated files from the former
|
||||
flat `DebugBridgeGenerated/` layout before emitting the current accessor.
|
||||
Generation accepts file-scope observable classes and JSON-native scalar,
|
||||
array, String-keyed dictionary, and Optional field types. It rejects custom
|
||||
types, implicitly unwrapped Optionals, nested observable classes, and duplicate
|
||||
snapshot keys before writing a completion marker.
|
||||
|
||||
The composite-hash cache key handles whether anything actually needs
|
||||
regenerating; if Swift version, generator git rev, lockfile, source content,
|
||||
and platform triple all match the cache, this is a ~50ms no-op.
|
||||
|
||||
## Phase 3: Update templated Swift files in place
|
||||
## Phase 3: Review the generated diff
|
||||
|
||||
For each file that comes from `ios-qa/templates/*.swift.template`:
|
||||
|
||||
1. Read the current installed file at
|
||||
`<app>/DebugBridgeGenerated/<Name>.swift`.
|
||||
2. Read the upstream template at
|
||||
`$GSTACK_HOME/ios-qa/templates/<Name>.swift.template`.
|
||||
3. If the installed file has a `// GSTACK-EDIT-LINE` marker, fold the user's
|
||||
edits forward.
|
||||
4. Otherwise, replace the file outright with the new template (after
|
||||
AskUserQuestion if the diff is non-trivial).
|
||||
1. Review changes under `<app>/DebugBridge/` and
|
||||
`<app>/DebugBridgeGenerated/StateAccessor.swift`.
|
||||
2. Confirm the command did not modify the app's handwritten Swift files.
|
||||
3. Keep app-specific wiring in the app target; canonical bridge package files
|
||||
are regenerated from upstream and should not be hand-edited.
|
||||
|
||||
## Phase 4: Verify
|
||||
|
||||
@@ -91,5 +95,6 @@ For each file that comes from `ios-qa/templates/*.swift.template`:
|
||||
| Symptom | Action |
|
||||
|---|---|
|
||||
| Swift compile fails after regen | Revert via `git restore` + AskUserQuestion: surface the compile error |
|
||||
| Schema hash unchanged after adding new @Observable | The new class isn't marked `@Snapshotable` — the codegen excludes it correctly. If the user wanted it snapshotted, add the wrapper. |
|
||||
| `--input` source dir contains test fixtures | gen-accessors scans the input dir recursively; exclude test/ via `--exclude` |
|
||||
| Codegen reports an invalid marked declaration | Use a file-scope observable class and a writable instance `var` with an explicit JSON-native type, internal/public setter, and a key unique across models; otherwise remove the `// @Snapshotable` marker. |
|
||||
| Schema hash unchanged after adding new @Observable | No field has the standalone `// @Snapshotable` marker comment — codegen excludes unmarked state correctly. Add the comment immediately above each field that should be snapshotted. |
|
||||
| Scanner sees generated bridge sources | Pass the narrow app source directory; the regenerator automatically excludes `DebugBridgeGenerated` and `StateAccessor.swift`. |
|
||||
|
||||
Reference in New Issue
Block a user