Files
apophis-fastify/docs/attic/root-history/FEEDBACK_APOSTL_PARSER_LIMITATIONS.md
T

8.4 KiB

FEEDBACK: APOSTL Parser Limitations Blocking Behavioral Contracts

From: Arbiter Team (opencode integration) Date: 2026-04-28 Severity: High - prevents adoption of Silver/Gold behavioral contracts Apophis Version: 2.x (latest)


Executive Summary

We've spent significant effort upgrading our route contracts from Bronze (tautological) to Silver/Gold (behavioral with cross-operation causality, data integrity, and state transitions). However, multiple documented APOSTL features fail at parse time, forcing us to strip contracts back to Bronze level or remove features entirely.

We cannot leverage the full power of Apophis as documented. This feedback documents exact parser failures with minimal reproductions.


Issue 1: x-requires Resource Identifier Syntax Fails to Parse

Documented Syntax (from getting-started.md line 227)

'x-requires': ['users:id']  // requires a user resource to exist

Actual Behavior

Parse Error:

Parse error at position 5: (found ':')
    users:userKey
         ^
Unexpected token

Impact

We cannot declare route preconditions. This breaks:

  • Observer routes that need resources to exist before testing
  • Mutator routes that should only run on existing resources
  • Destructor routes that require resources to delete

Workaround

We stripped ALL x-requires from our contracts. This means Apophis cannot know which routes depend on which resources, likely breaking stateful test generation.

Minimal Reproduction

app.get('/users/:id', {
  schema: {
    'x-requires': ['users:id'],  // FAILS
    'x-ensures': ['status:200']
  }
}, handler)

Expected Behavior

Either:

  1. The resource:id syntax should parse correctly, OR
  2. Documentation should show the correct APOSTL expression format for preconditions

Issue 2: route_exists() Inside Conditionals Fails to Parse

Documented Syntax (from getting-started.md line 742)

'route_exists(this).controls.self.href == true'

Actual Behavior

When used inside an if conditional (which is necessary since we only want to check hypermedia on success):

Parse error at position 31: (found '(')
    if status:200 then route_exists(this).controls.self.href == true else true
                                   ^
Expected "else"

Impact

We cannot validate hypermedia links in success cases. This breaks:

  • HATEOAS contract verification
  • Self-link validation
  • Action descriptor integrity checks

Workaround

Strip all route_exists() calls from contracts.

Minimal Reproduction

app.get('/users/:id', {
  schema: {
    'x-ensures': [
      // FAILS - parser chokes on route_exists inside conditional
      'if status:200 then route_exists(this).controls.self.href == true else true'
    ]
  }
}, handler)

Expected Behavior

route_exists() should be valid inside if expressions, or the docs should show the correct nesting syntax.


Issue 3: response_body(GET /path/{id}) Inside Conditionals May Fail

Observed Pattern

Cross-operation calls like:

'response_code(GET /users/{response_body(this).id}) == 200'

Work fine as top-level expressions. But we suspect nesting them inside conditionals may also fail (we haven't tested extensively due to Issues 1 and 2 blocking progress).

Question for Apophis Team

Are cross-operation calls valid inside if expressions? Example:

'if status:201 then response_code(GET /users/{response_body(this).id}) == 200 else true'

Issue 4: Lack of Clear Error Context

Problem

Parse errors show:

Parse error at position 5: (found ':')
    users:userKey

But they do NOT show:

  • Which route file caused the error
  • Which route definition (path/method)
  • Which specific contract clause failed

With 100+ routes, debugging requires binary search through files.

Expected Behavior

Parse error in route GET /tenant/users/:userKey
  File: src/routes/user-directory/index.js:150
  Contract: x-requires[0]
  Expression: 'users:userKey'
  Parse error at position 5: (found ':')

What We Had to Remove

Here's the complete list of behavioral contracts we WROTE but had to DELETE due to parser failures:

From user-directory/index.js:

// All x-requires (6 routes affected):
'x-requires': ['users:userKey']

// Hypermedia validation (2 routes affected):
'if status:200 then route_exists(this).controls.self.href == true else true'

From billing/subscriptions.js:

// x-requires (2 routes):
'x-requires': ['subscriptions:subscriptionId']

From billing/invoices.js:

// x-requires (3 routes):
'x-requires': ['invoices:invoiceId']

From notifications/email-routes.js:

// x-requires (3 routes):
'x-requires': ['notifications:notificationId']

// Hypermedia:
'if status:200 then route_exists(this).controls.self.href == true else true'

From webhooks-management/index.js:

// x-requires (12 routes):
'x-requires': ['webhooks:id']

From sessions-management/index.js:

// x-requires (3 routes):
'x-requires': ['sessions:jti']

From devices/*.js:

// x-requires (4 routes):
'x-requires': ['devices:id']

From workflow/index.js:

// x-requires (3 routes):
'x-requires': ['workflow_handoffs:id']
'x-requires': ['workflow_lineages:lineageId']

Total: 39 routes had behavioral contracts stripped due to parser limitations.


Current State After Workarounds

We've kept the behavioral contracts that DO work:

Cross-operation causality (top-level):

'response_code(GET /resource/{response_body(this).data.id}) == 200'

Data integrity (top-level):

'response_body(GET /resource/{response_body(this).data.id}).data.name == request_body(this).name'

Collection consistency (top-level):

'exists item in response_body(GET /resource).data: item.id == response_body(this).data.id'

State transitions (top-level):

'previous(response_body(GET /resource/{id}).data.status) != response_body(GET /resource/{id}).data.status'

Tenant isolation (top-level):

'for item in response_body(this).data: item.tenantId == request_headers(this)["x-tenant-id"]'

Deletion semantics (top-level):

'response_code(GET /resource/{request_params(this).id}) == 404'

All x-requires removed (39 routes affected) All route_exists() removed (6 routes affected) Cannot nest cross-operation calls inside conditionals (untested but suspected)


Recommendations

Immediate (P0)

  1. Fix x-requires parsing: Either support resource:id syntax or document the correct APOSTL expression format
  2. Fix nested expression parsing: Allow route_exists(), response_code(GET ...), etc. inside if conditionals
  3. Improve error messages: Include file path, route method/path, and contract clause index in parse errors

Short-term (P1)

  1. Add a contract validator CLI: npx apophis validate-contracts src/routes/**/*.js that reports all parse errors without running tests
  2. Document parser limitations: Clearly state which APOSTL features work in which contexts (top-level vs nested)

Long-term (P2)

  1. Consider JSON Schema integration: Auto-derive x-requires from required params fields
  2. Add IDE support: VS Code extension that highlights invalid APOSTL expressions at write-time

Context

We operate a large Fastify API (40+ route families, 200+ routes). Our goal is to have Gold-level behavioral contracts on every route. We've completed:

  • Explicit JSON Schema on all routes
  • x-category classification (constructor/observer/mutator/destructor)
  • Bronze-level contracts (status codes, error consistency)
  • Silver/Gold cross-operation contracts (where parser allows)
  • x-requires preconditions (blocked by Issue 1)
  • Hypermedia validation (blocked by Issue 2)

We want to be an Apophis success story. These parser issues are the only blockers.


Contact

This feedback was generated during active route decoration work. We're available to test fixes, provide more reproductions, or discuss syntax design.

Priority: Blocking production adoption of behavioral contracts Impact: 39 routes cannot express preconditions; 6 routes cannot validate hypermedia