AppSheet Parser and Orphan Detector Suite — a substantial update
I’ve just pushed a large batch of fixes to the parser suite, and I want to describe both what changed and where I think this is heading, because the second part has become more interesting to me than the first.
The immediate news: running the scripts against another creator’s app — shared with me generously for testing — the possible-orphan count came down from 105 to 54. Fifty-one of those were the scripts’ own errors, not actual orphans in his app. In other words, they were views that were reachable via routes the scripts couldn’t see.
What caused those errors is the part worth dwelling on. LINKTOFILTEREDVIEW wasn’t in the parser’s list of navigation functions at all. LINKTOFORM actions were excluded by an action-type filter. Map views had no visibility rule written for them. Two whole shapes of CONTEXT() condition — LEFT(CONTEXT(“View”), N) = “prefix” and IN(CONTEXT(“View”), LIST(…)) — were silently dropped, so the edges they restrict arrived looking unconditional. Every one of those was a rule that only ever got written for the cases my own app happened to exercise.
That is the structural problem with this kind of tool, and I don’t think more fixes solve it. A script has to anticipate every shape in advance. The next unanticipated one fails exactly as silently as the last, and you find out when someone else’s app surfaces it — if you’re lucky enough to have someone else’s app.
Which is why the direction I care about is making the app’s data legible to AI rather than making the script’s verdicts sharper. The scripts already output structured CSVs, and there is now a CLAUDE.md and AGENTS.md so an AI assistant reading them knows what each file means and what the suite cannot see. My aim is for a creator to be able to ask questions in plain language — “I made this action and expected it to show up on this view but it isn’t, find out why”, or “I’m looking at this view and can’t remember how a user gets here, tell me the ways” — and get a real answer.
Practical notes. STATUS.md is a public defect list. It records defects in the suite that are still open, defects already fixed and the commit that fixed each, and — separately — things the suite cannot establish at all, because AppSheet’s export doesn’t carry them.
If you run the scripts against your own app, I’d genuinely like to hear about what they missed or got wrong. Every gap fixed this month came from an app that wasn’t mine.
I’m hoping to publish the AI-ready version within a week or so.
Kirk
P.S. Here are some technical notes from Claude:
A concrete example of what the AI-legibility paragraph above is about, from Kirk’s own app this week. One of his actions carries this condition:
or(context(“View”)=“Session”, left(context(“View”),9)=“Session J”)
The parser’s only_if_condition handling scans the raw expression text with a regular expression and collects whatever CONTEXT() clauses it finds. It has no model of the boolean structure around them, so it captured the first alternative, dropped the second, and concluded the action was unavailable on a view where it plainly is available — confirmed by opening the app and looking.
The same flat scanning cuts the other way too. In a second case it accumulates two clauses that the expression’s own structure keeps apart, producing two navigation edges the app does not have. That is now recorded as a defect with both wrong rows named, rather than left as an approximation.
And a third shape defeats the pattern entirely. This one is not a view restriction at all:
IF(left(CONTEXT(“View”),20) = “Session confirmation”, NUMBER([Text2]) = [Number], TRUE)
The LEFT test selects which data condition applies; the else-branch is TRUE, so the action is available everywhere. A parser that hoisted every LEFT it found into a view restriction would wrongly refuse most of that action’s edges. Avoiding it required a special-case guard.
Fixing this properly means parsing boolean structure — building an expression tree, knowing that an OR unions and an AND intersects and an IF does neither. That is a real interpreter where there is currently a regex, and it would need re-verifying every condition the suite produces. For a volunteer project, that is a large cost for cases whose shapes cannot be enumerated in advance anyway.
The alternative Kirk is exploring: the raw expression is already preserved on every edge in the output, so a reader that understands AppSheet expressions can settle these directly. All three cases above are ones a language model reading the expression gets right, including the IF-with-TRUE-else-branch that defeated the regex.
One condition makes or breaks that approach, and it is not met yet. A condition mangled by an unparsed OR is byte-identical in the output to a cleanly parsed one — same six columns, same format. So a reader has no way to know which conditions to re-read and which to trust. The tool has to be explicit about what it could not interpret, or “check this one” is not available as an answer. That is the next design problem rather than a solved one, and it is why the defect list is public.