9.7 KiB
Read-only mixed CLI: independent critique
Research only against bab6f96a5b05b37f2b5d67a430aed0f67d783e73; no builds, application execution, production edits or remote actions. Reviewed implementation map SHA256 cb611919a1d6b6463f5e7054922d40457734305656e0dfff9dd4a1388a2c4ed7. References below are relative to that source. This selects a bounded next outcome, not acceptance of an implementation.
Recommendation
Implement explicit arcadia check-mixed ROOT [--json]: discover actual included files safely, then invoke the existing complete borrowed checker on captured original bytes. Require schema8 and explicit UUIDs, including ordinary declarations in this command. Return diagnostics through the existing report envelope, with no changes, migration, stabilization or write. This delivers useful command-line validation for the textual-model/linting goal in PROJECT_GOAL.md:64–69,96, while leaving editable model adoption separate.
check --mixed is also coherent, but offers no semantic advantage and requires more option-combination rules. Choose one spelling. Automatic replacement of check is unsafe: existing ordinary drafts intentionally accept omitted IDs and older versions. Schema8 alone cannot select between those policies. A manifest of every file is a simpler parser-free discovery interface, but transfers routine include enumeration to users and is not an equivalent root-file workflow. Full compile/index adoption is substantially larger and unnecessary here.
Simpler correct discovery policy
Prefer one shared discovery Budget and ModelCounts, with conservative completed-unit reservations retained until discovery ends. This is simpler than the map's proposed exact release/reconciliation seam. Do not describe its counters as exact live storage, an admitted syntax witness, or carry into the final verifier. Ordinary and public in-memory checker accounting must remain unchanged.
The source supports this narrower policy:
analysis_source/mixed.rs:390–422performs lexing and the sharedParser::unitusing one Budget/ModelCounts.lex.rs:15–68charges bytes, scanner events including trivia, and scanner temporary string work. State shares model counts and typed numeric parsing rather than creating a fresh per-file allowance.- Full parsing retains each completed unit, tokens and lexical owners, and additionally constructs positions (
mixed.rs:425–511). Dropping the discovery unit does not itself decrement Budget. Leaving its final charges reserved therefore remains an upper bound on live producer-domain storage; it does not create dangling ownership or an authority witness. Keep normal existing temporary/UUID/provisional-key releases within the parser unchanged. - For the same successfully parsed files and depth-first order, discovery uses the same unit grammar, U/token/reference/numeric events and transient string decoding as full parsing. Omitting position construction removes nonnegative metadata/text charges. Initial or incremental discovery file-slot reservations must be no greater than the full parser's F file slots, and must not charge already-visited paths again. Under these conditions, retaining completed-unit charges causes no additional producer-cap refusal relative to the corresponding successful full syntax parse, which retains those units anyway. This conditional argument does not promise identical failure precedence for invalid input or disk discovery.
- Both existing walkers push includes in reverse for source-order DFS (
source_files.rs:511–517,source_project/traversal.rs:179–183). Preserve that order and once-per-path inspection. Repeated authored edges still count; repeated targets do not get another syntax budget.
Name the phases explicitly: one bounded discovery syntax pass, followed by one independently bounded complete verification pass. Derive both profiles from the same original caller policy; do not expose arbitrary production profiles. In particular, numeric work is capped per named pass, not falsely advertised as one 50,000,000-unit command-wide allowance. Discovery Budget, parser state and all ordinary/typed/token owners must be dropped before full verification starts. Only loader-owned sources, bounded include/path bookkeeping and diagnostics survive. Do not retain an unnecessary parsed model or clone a complete syntax witness.
This reasoning covers the existing logical producer domains, not all Rust allocations, path bookkeeping, model heap, allocator capacity or RSS. Resolved include targets/locations belong to the existing bounded loader domain; do not call their transfer a producer-ledger reconciliation. Discovery never invokes the resolver or its exact syntax-inventory check. No new refund mechanism is needed merely to make already-freed units disappear from a conservative reservation.
An alternative fresh unit budget with explicit remaining aggregate work caps could also be correct, but requires transferring numeric/event usage and separating remaining work from per-unit storage limits. That is more machinery than retaining reservations. Fresh unrestricted per-file budgets are rejected: they silently multiply numeric and other work ceilings by file count.
Concrete failure obligation: existing discovery continues after inspect_includes failures (source_files.rs:519–521), whereas Budget::active (budget.rs:228) returns a latched Error containing a Span but no filename. Reusing that failed budget for a sibling would risk reporting the old span against the sibling. Select terminal mixed syntax/work failure: keep its first located diagnostic and perform no further unit parses using that budget. Still perform the selected final filesystem/journal checks. Preserve ordinary-path aggregation unchanged. Specify first-failure behavior rather than attempting to claim diagnostic identity with complete in-memory validation.
Disk ownership and safety
Reuse the existing logical-path, root-containment, regular-file, bounded-read, case/physical-alias and journal checks (source_files.rs:111–325,536–549). Before any read, enforce aggregate effective source bytes min(caller.model.max_source_bytes, 64 MiB); checking only the caller's possibly unlimited ceiling and rejecting later in the parser is insufficient. Pass the original ProjectLimits to final verification, without silently widening or replacing them.
For a fresh load, consume the discovered DiskProject into an opaque read-only { bundle, diagnostics } after final checks, dropping expectations/root/reachability. Every stored source was discovered from the entry; no overlay/detached-input preservation is needed. Avoid reachable_bundle() (source_files.rs:59–72), which clones all source strings. The existing temporary raw expectation bytes and UTF-8 strings are two bounded copies, not one accounted allocation; document reuse honestly. A smaller fresh-only storage owner may be a later optimization, not a prerequisite for this milestone.
Keep reserved journal names, pending-save refusal and no implicit recovery. Existing path checks do not establish an atomic multi-file snapshot or defeat every concurrent replacement race (source_files.rs:177); promise validation of captured bytes and no writes by this command. Do not broaden platform claims beyond actual tests. Fail discovery before invoking the complete checker on missing/invalid buffers.
Route this command before ordinary CLI prepare (oa-cli/src/lib.rs:213–310), which calls ordinary lint/ID analysis/compilation even for Check. An Arguments command branch is sufficient; do not add a fake SourceIndex, editable Prepared value, save conversion or mixed write option.
Falsifiable acceptance
- Real executable OA/SA multi-file fixtures: typed/scoped cross-file references, ordinary nesting, escaped includes, comments containing
include, Unicode and mixed CRLF. Compare complete diagnostics/report bytes and independently authored complete models for the same captured literals. Hash files and directory entries before/after; reject--writeand unknown options. - Discovery-budget tests: two files each individually below a tightened private numeric/event cap but jointly over it; repeated target inspected once; repeated edges counted; one shared ModelCounts limit across files; exact cap/cap-minus-one boundaries. Test-only profile tightening must not become caller-controlled public authority. Compare discovery producer reservations with the full parser at equivalent successful prefixes/fixtures, including quoted provisional releases and omitted projection charges.
- Failure attribution: first file triggers a latched budget refusal while a sibling remains queued; assert the original file/span once, no sibling reinterpretation and no final checker invocation. Include missing IDs in project, ordinary declaration, typed definition and parameter, plus unresolved/wrong-kind references reaching final verification.
- Existing filesystem invariants: bounded aggregate reads even with unlimited caller bytes; include depth/edges/files, invalid UTF-8, nonregular files, escapes/reserved names, case/physical aliases, cycles and pending journals. Preserve ordinary loader/CLI results. Pin mixed diagnostic precedence where discovery differs; platform-specific link/FIFO cases remain conditional.
- Verify actual normal-library/CLI boundaries and relevant finite stack controls after helper extraction. No universal headroom or full authoring claim follows from these checks.
No design blocker remains if the contract adopts the conservative reservation meaning, terminal failure rule, effective pre-read byte cap, and separate fresh final verifier above. The implementation must demonstrate those conditions; this report does not waive existing parser limits or substitute discovery success for complete semantic admission.