Skip to content

Baton: the #332 declared-signal principle applies to the Coherence Bridge — codescan's role=language heuristic is the same anti-pattern as title-scan #335

Description

@montfort

Context. Baton has two axes that the recent #332 turn touched very differently, and they share one underlying principle worth recording explicitly — so that when the next piece of work on the Coherence Bridge lands (notably #321, triggered at N=2), it is done under the lesson of the turn, not by re-deriving it.

This is a design-coherence note, not new functionality. It does not change scope already owned by #321 (the codescan generalization plan + its N=2 trigger). It records the why that should govern that work.

The two axes (for the record)

The shared anti-pattern: reconstructed-heuristic-calibrated-to-one-stack

The #332 turn discontinued the title-scan on the router axis. The root reason (decision #332, AILOG-2026-06-27-001) was not "keyword tuning is hard" — it was structural: inferring a unit's work type by substring over an unconstrained, schema-less title is calibrated to one adopter's titling habits, an unbounded per-adopter treadmill (the #321 "calibrated to one stack" anti-pattern). The fix was to prefer a declared signal at authoring (work_verb) over a posteriori reconstruction.

That is exactly the load-bearing smell #321 already identified on the Bridge axis: codescan hardcodes Go = producer, conflating language with architectural role. Role is not a property of language — it only looks that way because Sentinel's stack happens to be Go⇄TS. It is the same error as title-scan, in the other axis: a heuristic calibrated to the single dogfood oracle.

Both are the reverse of the same thesis (#328): prefer declared / explicitly-confronted structured signal over heuristic reconstruction.

  • The router now classifies declared work (work_verb) instead of guessing it from the title.
  • The Bridge already keys contracts by the normalized endpoint (scan::normalize_endpoint) — a declared, language-neutral anchor — and links intention to governance by explicit IDs, not textual similarity. That core is right. What is not aligned with the thesis is the stack-specific extraction around it (file-by-extension, Go = producer).

What this means for the Bridge (direction, not a redesign)

  1. Baton: language-agnostic contract-shape extraction (codescan is Go⇄TS-specific; decouple role from language) #321's generalization should be governed by this principle. When N=2 triggers it, infer producer vs consumer from signal (a serialization-tagged struct reachable from a route registration = producer; a type consumed at an HTTP call site = consumer), never from language. Follow the precedent the turn endorses and that Baton: language-agnostic contract-shape extraction (codescan is Go⇄TS-specific; decouple role from language) #321 already names: the config-driven, language-agnostic scanner pattern Loom shipped (architecture: in config.yml, architecture generate: language/structure-agnostic scanner — configurable extensions + container dirs (Java/Maven collapses to one 'main' box) #279) — i.e. let the adopter declare producer/consumer source globs + languages, rather than baking a stack assumption.
  2. Baton: producer-side route keying for handler-framework Go (huma route-registration ↔ output struct) #319 is consistent with the thesis and remains valid — it fixes structural reading (huma route-registration → output struct), not a keyword table. No change.
  3. Open question the turn raises (defer with Baton: language-agnostic contract-shape extraction (codescan is Go⇄TS-specific; decouple role from language) #321, do not act now): should the Bridge prefer a declared source of contract shape (OpenAPI / contract frontmatter) over heuristic code extraction, by the same cost/certainty argument as Decisión: descontinuar title-scan; work_verb declarado como única señal de clasificación #332? Baton: per-type → endpoint contract keying for generated type files (unblocks C2/C3) #313 chose "call-sites > parsing OpenAPI"; that choice is worth re-examining in the turn's light — but only once a real second stack is on the table.

Bridge ↔ routing (clarifying the relation, since it motivated this note)

By design (concept §10.6): "the router consults coherence before routing"coherence first, routing after (§3: a cheaper router over forgotten intent just automates drift faster). But that consult is design, not code today: the two subsystems are separate; the router does not consume Bridge findings. The concrete integration (a unit touching a drifted contract = risk signal → route up) was among the router's deferred heavy signals. The #332 turn established that the confidence lever is declared signal, not wiring those heavy signals — so Bridge→router integration stays a secondary/future cross-check, not the primary routing mechanism. Recorded here so the relation is not misread as an existing dependency.

What this issue does / does not do

Relation

#332 (the turn — title-scan axis) · #321 (codescan role=language — Bridge axis, the generalization) · #328 (structured-signal-is-the-lever thesis) · #333 (title-scan removal) · #304 (the umbrella the Bridge serves) · #319 (producer-side keying, consistent).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions