minor tweaks
This commit is contained in:
parent
fb652c39ae
commit
22ab973f0c
13 changed files with 223 additions and 144 deletions
94
src/main.rs
94
src/main.rs
|
|
@ -84,9 +84,11 @@ enum Cmd {
|
|||
},
|
||||
/// The whole per-game build in ONE in-memory command: derive → fold → (if `--game-dir` is given)
|
||||
/// validate-live + typed netvars → merge → fold model, writing the release set
|
||||
/// (`rosetta-<game>.json` + `model-<game>.json` + `manifest.json`) into --out-dir. No per-stage
|
||||
/// intermediate files. **Pass `--game-dir` for a full, live-validated build; omit it for a fast
|
||||
/// OFFLINE build (no server, so no live validation and a `null` schema).**
|
||||
/// (`rosetta-<game>.json` + `manifest.json`, plus `model-<game>.json` when `--corpus-model` was the
|
||||
/// source — the sidecar is that model rolled N → N+1, so a `--corpus` genesis run writes two files,
|
||||
/// not three) into --out-dir. No per-stage intermediate files. **Pass `--game-dir` for a full,
|
||||
/// live-validated build; omit it for a fast OFFLINE build (no server, so no live validation and a
|
||||
/// `null` schema).**
|
||||
Produce {
|
||||
/// A launchable game install → the FULL build (boots a server for validate-live + typed netvars).
|
||||
/// OMIT for an offline build. The offline/full switch — no separate flag.
|
||||
|
|
@ -98,12 +100,13 @@ enum Cmd {
|
|||
/// Server library to derive from; defaults to the active game's server lib.
|
||||
#[arg(long)]
|
||||
lib: Option<String>,
|
||||
/// One bundled seed (catalogue + naming sections) — the release form. Replaces the loose
|
||||
/// --catalogue/--promotable/--candidates/--full-names/--extra-offsets/--extra-sigs flags.
|
||||
/// One bundled seed (catalogue + naming sections) — the release form. Carries everything the loose
|
||||
/// --catalogue/--promotable/--candidates/--full-names/--extra-offsets/--extra-sigs flags carry, and
|
||||
/// CONFLICTS with each of them: pass one form or the other, never a mix.
|
||||
#[arg(long)]
|
||||
seed: Option<PathBuf>,
|
||||
/// Function catalogue (loose form; omit when using --seed).
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "seed")]
|
||||
catalogue: Option<PathBuf>,
|
||||
/// Corpus-signal source A: the raw build binaries to fingerprint on the fly. Exactly ONE of
|
||||
/// --corpus / --corpus-model is required (--corpus-model is the production forward-derive path).
|
||||
|
|
@ -119,22 +122,22 @@ enum Cmd {
|
|||
target: PathBuf,
|
||||
/// Optional: names eligible for promotion into high_confidence (from the naming producer flow).
|
||||
/// Omit to promote nothing — the catalogue still derives in full.
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "seed")]
|
||||
promotable: Option<PathBuf>,
|
||||
/// Optional: prefiltered per-address context for those names (`{"candidates": [...]}`). Omit for none.
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "seed")]
|
||||
candidates: Option<PathBuf>,
|
||||
/// Optional: the full-slice name universe. When set, the monolith also carries an `experimental`
|
||||
/// tier — the least-filtered inclusion band (every name guess, graded, each with a resolvable
|
||||
/// locator but an UNVERIFIED name).
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "seed")]
|
||||
full_names: Option<PathBuf>,
|
||||
/// Multilib ground-truth vtable offsets to fold as high_confidence — `{lib: [{name,class,slot}]}`
|
||||
/// (e.g. the macOS symbol transfer). Folded directly, bypassing the candidate gate.
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "seed")]
|
||||
extra_offsets: Option<PathBuf>,
|
||||
/// Multilib non-virtual names to fold as sigs — `{lib: [{name,addr}]}`; `make_sig` runs per lib.
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "seed")]
|
||||
extra_sigs: Option<PathBuf>,
|
||||
/// Declared C++ prototypes (`mappings/prototypes.json`) to judge against this build's measured
|
||||
/// register footprints. Static repo input — omit and no function carries a declared prototype.
|
||||
|
|
@ -171,12 +174,12 @@ enum Cmd {
|
|||
/// Distill the whole corpus into a shippable model (vtable-alignment hops + reference fingerprints
|
||||
/// + slot timelines) so derivation needs only the model + the target binary, not the 86 GB corpus.
|
||||
CorpusModel {
|
||||
/// One bundled seed — the release form; its catalogue section is what gets distilled. Replaces the
|
||||
/// loose --catalogue (naming sections are ignored here — the model tracks catalogue names only).
|
||||
/// One bundled seed — the release form; its catalogue section is what gets distilled. CONFLICTS with
|
||||
/// the loose --catalogue (naming sections are ignored here — the model tracks catalogue names only).
|
||||
#[arg(long)]
|
||||
seed: Option<PathBuf>,
|
||||
/// Function catalogue (loose form; omit when using --seed).
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "seed")]
|
||||
catalogue: Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
corpus: PathBuf,
|
||||
|
|
@ -195,11 +198,12 @@ enum Cmd {
|
|||
/// The existing model N (carries the `abi_obs` window the fold re-windows).
|
||||
#[arg(long)]
|
||||
model: PathBuf,
|
||||
/// One bundled seed — the release form; its catalogue section is folded. Replaces the loose --catalogue.
|
||||
/// One bundled seed — the release form; its catalogue section is folded. CONFLICTS with the loose
|
||||
/// --catalogue.
|
||||
#[arg(long)]
|
||||
seed: Option<PathBuf>,
|
||||
/// Function catalogue (loose form; omit when using --seed). Must match the model's distill catalogue.
|
||||
#[arg(long)]
|
||||
#[arg(long, conflicts_with = "seed")]
|
||||
catalogue: Option<PathBuf>,
|
||||
/// The one new build dir to fold in (holds the just-updated libserver.so etc.).
|
||||
#[arg(long)]
|
||||
|
|
@ -309,9 +313,11 @@ fn lib_or_default(prof: &profile::GameProfile, lib: Option<String>) -> String {
|
|||
}
|
||||
|
||||
/// Resolve the catalogue for the model commands (`corpus-model`/`fold-model`) from either a `--seed` bundle
|
||||
/// (release form) or a loose `--catalogue` file. The seed's catalogue section parses to the same functions as
|
||||
/// the loose `needed-functions.json`, so the distilled/folded model is identical either way. When a seed is
|
||||
/// given, its sections unpack under a `.seed` dir beside `out` (as `produce` does beside its out-dir).
|
||||
/// (release form) or a loose `--catalogue` file — never both; `catalogue` declares the conflict, so the
|
||||
/// `None` arm here means the flag was genuinely absent. The seed's catalogue section parses to the same
|
||||
/// functions as the loose `needed-functions.json`, so the distilled/folded model is identical either way.
|
||||
/// When a seed is given, its sections unpack under a `.seed` dir beside `out` (as `produce` does beside
|
||||
/// its out-dir).
|
||||
fn model_catalogue(
|
||||
prof: &profile::GameProfile,
|
||||
seed: Option<PathBuf>,
|
||||
|
|
@ -393,6 +399,9 @@ fn main() -> Result<()> {
|
|||
bots,
|
||||
} => {
|
||||
// derive inputs come from a single --seed bundle (release form) or the loose flags (dev/verify).
|
||||
// The bundle arm reads NONE of the loose bindings, which is only honest because each of them
|
||||
// declares `conflicts_with = "seed"` — clap rejects the mix before dispatch rather than letting
|
||||
// this arm drop an explicitly passed input on the floor.
|
||||
let inputs = match seed {
|
||||
Some(s) => unpack_seed(profile, &s, &out_dir.join(".seed"))?,
|
||||
None => SeedInputs {
|
||||
|
|
@ -511,3 +520,50 @@ fn main() -> Result<()> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use clap::CommandFactory;
|
||||
|
||||
/// A dropped input is a silent skip, and this is the one place the CLI could produce one: the `--seed`
|
||||
/// arms unpack every loose input themselves and never read the loose bindings, so an undeclared
|
||||
/// conflict means `produce --seed s.json --full-names f.json` runs to exit 0 with `--full-names`
|
||||
/// ignored — and a monolith with no experimental tier is exactly what a game with no naming harvest
|
||||
/// legitimately ships, so no collapse floor downstream can tell the two apart.
|
||||
#[test]
|
||||
fn a_seed_bundle_refuses_the_loose_inputs_rather_than_ignoring_them() {
|
||||
Cli::command().debug_assert();
|
||||
let parse = |argv: &[&str]| {
|
||||
let full: Vec<&str> = std::iter::once("source2rosetta")
|
||||
.chain(argv.iter().copied())
|
||||
.collect();
|
||||
Cli::try_parse_from(&full)
|
||||
};
|
||||
let refused = |argv: &[&str]| {
|
||||
assert!(
|
||||
parse(argv).is_err(),
|
||||
"accepted, so one of these inputs is silently dropped: {argv:?}"
|
||||
);
|
||||
};
|
||||
let produce = ["produce", "--target", "t", "--out-dir", "o", "--seed", "s"];
|
||||
for flag in [
|
||||
"--catalogue",
|
||||
"--promotable",
|
||||
"--candidates",
|
||||
"--full-names",
|
||||
"--extra-offsets",
|
||||
"--extra-sigs",
|
||||
] {
|
||||
refused(&[&produce[..], &[flag, "x"]].concat());
|
||||
}
|
||||
let model = ["--out", "o", "--seed", "s", "--catalogue", "c"];
|
||||
refused(&[&["corpus-model", "--corpus", "c"][..], &model].concat());
|
||||
refused(&[&["fold-model", "--model", "m", "--build", "b"][..], &model].concat());
|
||||
// Either form ALONE still parses — the conflict must not have made the loose form unusable.
|
||||
assert!(parse(&produce).is_ok());
|
||||
let loose = ["--catalogue", "c", "--full-names", "f"];
|
||||
let bare = &produce[..produce.len() - 2]; // the same command minus `--seed s`
|
||||
assert!(parse(&[bare, &loose[..]].concat()).is_ok());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue