14 KiB
Native textual definition/reference navigation
Codex-9e8r6t /root/behavior_audit, 2026-09-11. Read-only design against the local source7 desktop after ca53f574. Read issue1/current comments, empty open PR inventory, Authoring20260911 and peer BehaviorAuthoring20260911 Wiki, plus the textual usability audit and language design. Coordination: issue1 comment296. Only this report was written; no production, compiler, native or Git actions. Counterexamples below are source-derived acceptance cases, not executed tests.
Recommended slice
Add Go to definition, Find references, and Back inside the current Text page. Resolve the exact current token against declarations in the loaded text; use accepted UUIDs only as proven identity anchors. Preserve all buffers, pending forms, model/source history and filesystem expectations. Navigation must never Apply, stabilize, rename, load files or save implicitly.
This closes the concrete task “follow a scenario's @callee, inspect its lifeline, and return to the same caller expression” without requiring a diagram or manual file search. Source alias rename already has a separate shipped CLI; its absence in the earlier audit is historical. Refactoring, completion, scoped source8 names and metamodel changes are outside this slice.
Existing seams and their actual limits
| Production seam | Reusable behavior / limit |
|---|---|
source_navigation.rs:29 |
Literal active-buffer search already uses UTF-8 byte columns, selection and wrapping; no semantic symbol lookup or navigation stack. |
source_workspace.rs:83,183,243,283 |
Buffers retain raw text, baseline, cursor and independent text history. switch preserves drafts. accept replaces accepted buffers; navigation must not call it. bundle() includes detached buffers too. |
source_project.rs:92 |
SourceIndex maps UUIDs to declaration/body locations, lexical owners, top-level fields and includes. It has no individual reference-token index. All spans refer to CompiledSourceProject.bundle, after inserted IDs and possible migration (:285). |
model.rs:1727; references.rs:5,11 |
Project::identities() covers project, elements, relations, diagrams, nodes, artifacts and traces. Typed reference visitors give semantic IDs, including implicit ownership, but no source spans and no complete textual occurrence count. |
language.rs:145,1965 |
tokenize gives exact tolerant byte spans, excluding prose/comments by class. analyze additionally returns declaration aliases, optional explicit IDs, kinds and whole declaration spans, even before later syntax errors. However, it also calls standalone lint with unlimited parse limits (:230); it is not a cheap syntax-only index API. Missing-ID parses can allocate temporary UUIDs. |
app.rs:2795,2919,3672; views.rs:1176 |
File switching and diagnostic jumps already reveal file-tree ancestors and restore editor position. jump_to_source currently clamps an unversioned offset into the current buffer and selects a whole line; its SourceViewport receipt is unscoped. New symbol jumps need current ranges and context guards. |
app.rs:2948,3600 |
SourceForSelection calls property apply() before navigation: do not reuse that mutation boundary. An invalid Open installs a repair workspace with applied=false while retaining the previous accepted model; accepted symbols must never leak into that workspace. |
The diagnostic's displayed column counts Unicode scalars; Span and Iced editor positions count UTF-8 bytes. Convert from the exact source bytes, not the diagnostic line/column pair.
Alternatives and selected combination
| Approach | Useful result | Concrete failure if used alone |
|---|---|---|
| Accepted UUID → SourceIndex | Correct identity and declaration location for the exact accepted bundle, including repeated display names. | Insert a comment before the destination, or navigate an unstabilized buffer whose compile inserts IDs: the accepted byte offset lands elsewhere. An invalid newly opened project can share aliases with the previous model. Refusing every dirty workspace would also block useful navigation because an unrelated file is unfinished. |
Current lexical @alias → current declaration headers |
Works with incomplete, missing-ID and moved declarations without adopting them. | Global aliases can collide across files; BTreeMap<alias, declaration> silently loses one. Detached files can imitate a project declaration. A lexical token inside an invalid field is not proof of a valid typed reference. |
| Current lexical locations + explicit provenance + optional unique UUID anchor | Exact visible destinations while raw drafts remain intact; accepted identity is available when demonstrable. | Requires multimap ambiguity handling, a declared search scope, and revalidation of queued results. These are part of this slice, not later hardening. |
Do not run compile_bundle merely to navigate: it can stabilize/migrate the returned candidate and move positions. Do not treat Workspace::reachable as a tolerant outline service: it uses strict include parsing and can fall back to compilation. Do not resolve by display name, filename, nesting or guessed namespace.
Concrete interaction and query contract
- A compact Navigate menu beside Find exposes Definition, References and Back; keyboard candidates are F12, Shift+F12 and Alt+Left. Shortcuts act only in the focused source editor; a Find input, modal or another page keeps input priority. A single bounded, independently scrollable results panel leaves the editor usable and closes with Escape. One verified definition jumps directly; duplicate or unverified candidates require explicit selection. Reference results stay open while inspecting multiple uses.
- Capture an immutable query snapshot of the current loaded buffers, document/workspace session, entry, source revision and active cursor. Recognize a declaration header alias or
@plus the next nontrivia alias token. Whitespace and//comments may separate them. Hit testing includes the@and alias tokens, not intervening comments. Select the actual alias span at the destination. Usevalid_aliaswith token text, not onlyTokenClass::Identifier: the parser permits some aliases which the highlighter classifies as keywords, such asoa_activity. - Keep
alias -> Vec<Definition>andexplicit UUID -> Vec<Definition>. Never collapse collisions. Missing IDs remain missing; no UUID allocation or same-name correspondence is allowed. A header without a stable ID is anchored only to its path/range/snapshot. Show current header name/kind, full logical file/line and any authored ID. Accepted owner metadata, if displayed, must be labeled as last applied when drafts differ. - Scope is explicit. A coherent applied bundle can show Project references. For changed/invalid include syntax or unavailable documents, show References in loaded drafts — incomplete project scope, plus the file count. Search current loaded text, label detached candidates separately and do not auto-select them as a project definition.
workspace.reachablemay be stale after edits; it alone cannot certify current membership. Strictinspect_includesmay certify a complete current loaded closure; failure leaves the useful draft list available. Missing includes remain missing until the user invokes the existing Load includes action; no filesystem scan or implicit read. - On valid accepted source, lexer-recognized
@aliasuses resolve through the complete identity table. In changed/invalid text, label them unvalidated draft uses. Find references means authored live@aliasoccurrences, retaining separate repeated occurrences in the same field/file. It does not mean all dependencies: lexical ownership can imply a parent without an@token, and historical semanticuuid "…"leaves deliberately are not live aliases (language/semantic_source.rs:12). Comments, strings and longer aliases never count. - Every result carries query/session and source stamps, target identity when unique, logical path and exact span. Before clicking, re-resolve against current text or report that the results changed; never use an old list index or clamp a stale span. An alias reused by a different ID must not inherit the old target. Use document/workspace session, not Project UUID alone. Scope the deferred editor reveal/focus operation to the live Text page, exact file/buffer version, mounted editor and request token, including modal priority. A delayed result cannot steal focus after another navigation or document Open.
- Back is a separate bounded stack (64 entries) of logical path, cursor/selection, buffer generation and optional unique identity anchor. Push only after a successful jump; failed queries and Back itself add no entry. For an unchanged origin restore its exact selection and reveal it. If that buffer changed, open its current retained cursor with an explicit changed-position notice; do not pretend an old offset is exact. Keep file text Undo/Redo and model Undo/Redo untouched. Clear navigation state on document/recovery replacement or changed Save As root; do not persist queued jobs in crash recovery.
Small implementation partition
- Pure source query: new desktop
source_navigation/symbols.rs, snapshot/multimap/reference projections and bounded result enumeration. Reuse the existing declaration walk through a small syntax-only, bounded outline entry point separated fromanalyze's lint call. This is the sole proposed core API seam; coordinate it with peer956 before editinglanguage.rs. It changes no grammar/namespace/identity rules and should serve both existinganalyzeand navigation, avoiding a second handwritten parser. Budget bytes, tokens and index records before allocation; over-budget results must say incomplete, never “0 references”. - Navigation adapter:
source_navigation.rsplus narrowsource_workspace.rsgeneration bookkeeping and App jump/result guards. A worker task computes indexes on request, caches by exact buffer generation and discards superseded results. No project-wide parsing on every keystroke. Active typing invalidates the relevant cache without replacing any raw buffer. - View/tests: bounded menu/results in
views.rs, exact range selection and mounted editor reveal/focus tests. Root owns shared App integration and native acceptance. Peer956 retains scenario focus, unified canvas and source8/scoped-definition ownership; extend navigation to future syntax only through their supported lexical contract.
Falsifiers required before adoption
| Fixture/action | Required result |
|---|---|
Two modules contain same-named Activities with aliases north/south; source contains @north, @northbound, quoted "@north" and // @north. |
Only the exact live token resolves to north. Definition rows distinguish kind/file/ID; no name matching or prose hits. Include a legal keyword-classified alias. |
Prepend CRLF and 雨 before a dirty target; use @ // rationale\r\n north. Also place a missing-ID header before the use. |
Jump/selection uses current byte positions. Neither accepted/stabilized offsets nor scalar columns are substituted; no ID is inserted. |
| Copy one declaration into another included file; separately duplicate its UUID under a different alias. | Ambiguity/duplicate identity is visible, never first-match overwrite. A unique missing-ID declaration remains a draft anchor. |
| Move a declaration with its explicit ID to another loaded file while an unrelated buffer is invalid; then rename its alias and reuse the old alias for another ID. | Current destination is found or offered as a draft candidate; old alias/ID association never follows the new object. All raw files and their text histories remain exact. |
Invalid Open has applied=false; old accepted model has the same alias and even the same Project UUID. |
Only the new workspace is searched. No previous-model definition or stale result is offered as its binding. |
| Remove/change an include, leave a detached duplicate, or reference a not-yet-loaded file. | Honest loaded/partial scope and detached labeling; no false complete count, automatic loading, inferred namespace or source mutation. |
| ScenarioUse has callee, referenced/local lifeline pairs and repeated step references; trace baseline contains historical UUIDs. | Each authored @ occurrence appears separately; no collapsing by owner/target. Historical UUIDs and implicit nesting are not mislabeled as live textual uses. |
| Start a query, edit/close its target, switch documents or open a modal before the result/reveal executes. | Revalidation or safe refusal; no jump/focus in a different document, hidden page or modal. Test real mounted TextEditor input and deferred widget operations, not only App message matching. |
| Definition → reference → Back with Unicode selection; edit the origin before another Back. | Exact unchanged-origin selection; explicit changed-position behavior otherwise. Accepted Project/SourceBundle, every raw buffer, text/model history and disk expectations are identical before/after navigation. |
| 100 modules, 1,000 definitions with repeated display names and 10,000 explicit uses. | Keyboard remains responsive; report query latency, cache rebuild count and bounded index/result memory. Exceeding a budget yields an explicit incomplete result, not a complete empty search. No performance pass is claimed here. |
Reviewed SHA256 pins: source_navigation C1DA10882F35F8EB0675E68C642C9A209DDE09679CDED414CFB9903A4E49EC77; source_workspace 30F63A6B8D65A38D66061F90D864B5746CBACC0FBD65ABC028A8F3071C47D358; language 638F08A42E9CF4996B5D07F69B4D6F517A518369F3604D25BE1006E40E080765; source_project 1394370BCC5908873B830C2C11312E6E1611AF41F46C4F43CA0A6BCB713BB466.