Define bounded mixed source CLI validation contract
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
# Mixed CLI read-only check: implementation map
|
||||
|
||||
Design only against public-read branch bab6f96a (parent reports accepted gates).
|
||||
No source edits, compiler or remote actions. Paths/lines refer to this source.
|
||||
|
||||
## Recommended user outcome
|
||||
|
||||
Add explicit `arcadia check-mixed ROOT [--json]`, requiring the public checker's
|
||||
schema8 and explicit UUIDs. Preserve check/lint/stabilize/rename-alias behavior.
|
||||
Use the existing report envelope with operation check-mixed, status checked or
|
||||
invalid, no changes, written=false, migration=null and identities_to_stabilize=0.
|
||||
The operation validates captured original bytes; it does not stabilize, export,
|
||||
format, index or save. Help must state this distinction and reject --write.
|
||||
|
||||
The command choice and discovery architecture are separate decisions. Merely
|
||||
adding a command enum variant does not make the existing loader support typed
|
||||
syntax. A real parser-consistent discovery seam is the prerequisite below.
|
||||
|
||||
## Current blockers and reusable code
|
||||
|
||||
- oa-cli/src/lib.rs:213 prepare loads source_files::load_project, then ordinary
|
||||
lint/analyze/compile (234–310). Operation::Check still returns Prepared holding
|
||||
CompiledSourceProject and a disk snapshot; it is not a read-only mixed route.
|
||||
- main.rs:76 dispatches all accepted arguments through prepare and optional write.
|
||||
Add a separate report-returning mixed-check branch before that branch. Do not
|
||||
forge Prepared or an empty SourceIndex. An explicit Arguments command enum can
|
||||
separate read-check from existing editable Operation, or use a distinct
|
||||
check_mixed flag/variant handled before prepare; avoid illegal write combinations.
|
||||
- source_files.rs:329 load_project creates a DiskProject then discover_missing.
|
||||
Discovery's DFS reads bounded bytes and tracks originals/expectations (389–494),
|
||||
but495 calls ordinary inspect_includes and529 runs ordinary compile_bundle.
|
||||
- source_project.rs:207–268 inspect_includes validates paths and calls ordinary
|
||||
language::parse_unit, so it rejects valid short typed declarations. Filtering
|
||||
that diagnostic cannot reveal the missing include graph safely.
|
||||
- mixed.rs:390–422 already lexes and invokes the shared Parser::unit with actual
|
||||
mixed State and explicit IDs, producing ordinary.includes plus typed syntax.
|
||||
This exact unit grammar can inspect includes without resolving global references.
|
||||
Extract/reuse this narrow unit operation instead of a regex, guessed brace
|
||||
scanner, second quote decoder or calling the complete checker on partial bundles.
|
||||
- source_files.rs:104–216 root_entry/check_logical/disk_path/read_bounded already
|
||||
enforce root containment, canonical logical names, reserved journal namespace,
|
||||
link/regular-file restrictions and bounded reads.240 check_snapshot and293
|
||||
check_physical_aliases preserve aggregate and physical-alias checks. Reuse these
|
||||
functions in one core discovery engine; do not replicate their security logic in CLI.
|
||||
|
||||
## Minimal safe ownership shape
|
||||
|
||||
Introduce a named read-only discovery entry in source_files, with a small private
|
||||
closed selector OrdinaryEditable / MixedRead for shared discovery dispatch.
|
||||
Existing public discover_missing/load_project select OrdinaryEditable and retain
|
||||
all current completion/lint behavior. MixedRead selects mixed include inspection
|
||||
and skips ordinary compile/stabilization; it still performs all disk/path/journal
|
||||
checks. No generic caller-provided parser/loader callbacks or new public framework.
|
||||
|
||||
Prefer an opaque owning `MixedSourceSnapshot` exposing only bundle() and
|
||||
load_diagnostics(), or a narrowly scoped `load_mixed_source` result owning those
|
||||
values. Do not advertise it as a save snapshot or provide conversion into editable
|
||||
CompiledSourceProject. Internally reusing DiskProject's captured bytes is possible,
|
||||
but returning DiskProject publicly would unnecessarily expose save/discovery
|
||||
operations and expectations. Keep original raw-byte expectations private if reused.
|
||||
This design adds a small wrapper, not a clone of every buffer for an extra model.
|
||||
|
||||
CLI owns the snapshot, borrows its complete reachable SourceBundle while calling
|
||||
language::check_mixed_bundle, maps warnings/errors into the existing Report, then
|
||||
drops CheckedMixed before dropping source. Report owns mapped diagnostic strings;
|
||||
no borrowed checker escapes and no self-referential source/result struct is needed.
|
||||
Report has no Project field: complete model evidence comes from independent core
|
||||
and CLI-library tests of those same literals, not an invented JSON assertion.
|
||||
|
||||
## Discovery parser work and limits: resolve before implementing
|
||||
|
||||
Discovery is an extra syntax pass; final borrowed checker remains the sole complete
|
||||
semantic admission. Its existing budgets must be fresh for that full pass; do not
|
||||
subtract discovery work from final counts or represent a successful partial scan
|
||||
as an admitted model. Re-reading/reparsing captured strings is explicit bounded work,
|
||||
not a claim that the checker itself reparses or that disk is reread between phases.
|
||||
|
||||
The mixed unit helper needs a genuine Budget and ModelCounts. A naïve new budget
|
||||
per file silently multiplies allowed discovery numeric/token/reference work by the
|
||||
file count; a single shared budget with all retained-text totals left charged after
|
||||
units are dropped misrepresents live storage. Therefore contract must choose a
|
||||
small explicit **discovery-phase work policy** and lifetime:
|
||||
|
||||
- Recommended: one shared discovery work budget across all captured file parses,
|
||||
cumulative bytes/tokens/references/numeric/syntax-event work, with per-unit syntax
|
||||
owners dropped after copying only include locations. Reuse Parser::unit and its
|
||||
resource checks. Name and check temporary per-unit metadata/text ownership before
|
||||
growth if selecting producer mode; reconcile/release it on unit destruction.
|
||||
This is a real small producer-lifetime seam to specify, not existing free behavior.
|
||||
- Simpler alternative: per-unit bounded inspection with a documented aggregate
|
||||
upper bound of max_files times its cap. It is finite but can be far larger than
|
||||
the selected checker work profile; do not choose it silently or describe it as
|
||||
inheriting one whole-project numeric budget. Parent may reject that cost policy.
|
||||
- Do not retain all parsed witnesses then clone/reparse the complete bundle merely
|
||||
to avoid accounting a dropped unit. That grows live state and complicates source
|
||||
lifetimes for no consumer benefit. Do not stream-load into a borrowed BTreeMap
|
||||
while previously parsed units retain references into it; ordinary Rust borrowing
|
||||
disallows this without additional ownership infrastructure, which is unnecessary.
|
||||
|
||||
The implementation contract should pin the selected discovery bound/diagnostic
|
||||
order and helper's drop/refund rules before source edits. This is the main remaining
|
||||
bounded design question, not an argument for full editable-source adoption.
|
||||
|
||||
## Filesystem and diagnostic contract
|
||||
|
||||
Preserve existing root/file checks, UTF-8 rejection, aggregate byte/file/edge/depth
|
||||
limits, case/physical alias refusals and pending-journal detection. Root depth0;
|
||||
include paths resolved by existing resolve_include; count repeated authored edges.
|
||||
Final complete check still rejects cycles/semantic failures using its exact original
|
||||
coordinates. Discovery diagnostics prevent invoking checker with missing/invalid
|
||||
buffers. Return exit3 for disk/path/pending-journal failures under existing CLI
|
||||
mapping; exit1 for source/semantic rejection,0 for valid with advisory warnings,
|
||||
2 for invalid arguments. Pin mixed loader's diagnostic precedence in tests rather
|
||||
than assuming it equals in-memory checker's earlier/later limit branch.
|
||||
|
||||
Do not suppress pending_save simply because operation is read-only: existing CLI
|
||||
refuses it, and the captured files may represent interrupted save state. No journal
|
||||
recovery is implicit. Neither old nor new read path promises atomic multi-file
|
||||
snapshot/CAS against concurrent external replacement (source_files.rs:177 comment).
|
||||
Promise unchanged bytes by this command and validation of captured bytes, not
|
||||
that the disk still equals that snapshot after a concurrent editor writes.
|
||||
|
||||
## Compared/rejected options
|
||||
|
||||
- Automatically replace ordinary check with mixed: breaks existing omitted-ID and
|
||||
migration behavior. Schema8 alone does not distinguish ordinary drafts from the
|
||||
stricter explicit-ID mixed contract. Avoid heuristic detection/fallback on errors.
|
||||
- `check --mixed`: coherent alternative explicit spelling, but adds an option whose
|
||||
invalid combinations must be excluded for mutations. Dedicated check-mixed makes
|
||||
the limited outcome easier to explain; select one spelling, not both initially.
|
||||
- Explicit all-files CLI manifest/bundle: can reuse checker immediately, but forces
|
||||
users to enumerate includes and introduces another input/argument format. It is
|
||||
useful only if a real pipeline already supplies bundles; not the recommended
|
||||
ordinary filesystem workflow and not a substitute for safe include loading.
|
||||
- Full compile_bundle adoption: requires typed stabilization/index/update/formatter
|
||||
and application consumers; none is necessary for this read-only outcome.
|
||||
|
||||
## Finite acceptance and scoped files
|
||||
|
||||
Core changes: source_files shared discovery selector + read-only snapshot;
|
||||
language mixed unit inspection helper and narrow reexport for core-only use;
|
||||
source_project include-location conversion reuse where appropriate. CLI lib
|
||||
arguments/report path + main dispatch, docs/source-cli.md/help, focused tests.
|
||||
No changes to updater/save/formatter or public CheckedMixed authority.
|
||||
|
||||
Test actual executable on independently authored OA/SA three-file fixtures with
|
||||
cross-file typed/scoped references and ordinary nesting. Exact complete JSON
|
||||
warning/error reports, raw original byte hashes/directory listing unchanged after
|
||||
each command, including CRLF/Unicode and comments mentioning include/aliases.
|
||||
Core tests compare independently authored full models for those same bytes.
|
||||
|
||||
Exercise missing/cyclic include, invalid path/root escape, case/physical aliases,
|
||||
nonregular/invalid-UTF8 file, pending journal and exact aggregate/depth/edge limits.
|
||||
Only claim platform-specific link/FIFO tests where cfg permits; Linux remains
|
||||
user-deferred. Exercise missing IDs in all four classes and typed unresolved/wrong
|
||||
kind errors. Verify --write rejection and all existing ordinary CLI commands remain
|
||||
unchanged. No fake success for an empty include graph or wrong command dispatch.
|
||||
Add unit-hook counter/lifetime evidence for the chosen discovery work policy and
|
||||
repeat relevant existing filesystem/stack regressions after shared-loop factoring.
|
||||
|
||||
Parent decisions needed: command spelling; explicit discovery work/storage policy
|
||||
above; whether reuse of private DiskProject storage under opaque wrapper is worth
|
||||
its duplicated captured bytes versus a smaller read-only buffer owner. No source
|
||||
or compiler work is authorized by this proposal.
|
||||
Reference in New Issue
Block a user