Compare commits

..
Author SHA1 Message Date
sorokin.oleg.edu 8c2152c89b Sync agent instructions from main 2026-09-13 11:39:58 +03:00
sorokin.oleg.edu 91fa1b78f3 Record published rename preview and update integrated checkpoint 2026-09-12 17:52:46 -07:00
sorokin.oleg.edu 506a349b32 Preserve packaged rename acceptance and independent evidence reviews 2026-09-12 17:39:56 -07:00
sorokin.oleg.edu d12b0a6b75 Preserve corrected preview and current server verification 2026-09-12 17:01:20 -07:00
sorokin.oleg.edu cbc49a7802 Reset alias preview scroll for each explicit destination 2026-09-12 15:51:09 -07:00
sorokin.oleg.edu 4686d05003 Record completed native Text alias rename verification 2026-09-12 15:37:10 -07:00
sorokin.oleg.edu dfb6102ba5 Add guarded Text alias rename with complete preview and editor reuse 2026-09-12 15:01:08 -07:00
sorokin.oleg.edu be7a8cd8d7 Publish verified navigation Windows prerelease checkpoint 2026-09-12 03:58:54 -07:00
sorokin.oleg.edu f5e1c734da Record independent package and native Windows navigation acceptance 2026-09-12 03:51:26 -07:00
sorokin.oleg.edu 9613cf71aa Sync agent instructions from main 2026-09-12 13:43:44 +03:00
sorokin.oleg.edu 08350bb3f4 Sync agent instructions from main 2026-09-12 13:40:27 +03:00
sorokin.oleg.edu 36c105f3cd Sync agent instructions from main 2026-09-12 13:16:07 +03:00
sorokin.oleg.edu c5ea82ed50 Preserve navigation Windows package preparation and exact source provenance 2026-09-11 14:24:43 -07:00
sorokin.oleg.edu 8cf64cedb2 Verify repair and recovery save state in native Windows workflows 2026-09-11 14:12:09 -07:00
sorokin.oleg.edu 33c6d83e9b Bind repaired source save state to its actual destination 2026-09-11 13:43:37 -07:00
sorokin.oleg.edu 1e63dd69ed Choose guarded worker preparation for Text alias rename 2026-09-11 13:42:07 -07:00
sorokin.oleg.edu 00a21d3322 Record corrected navigation trial and alias transaction measurements 2026-09-11 13:34:48 -07:00
sorokin.oleg.edu eeeaa12627 Fix native Text navigation layout and focus regressions 2026-09-11 12:44:17 -07:00
sorokin.oleg.edu f4e426ae2a Preserve preliminary alias-rename preview timing and unchanged inputs 2026-09-11 12:14:38 -07:00
sorokin.oleg.edu fb16c4200f Record Text alias rename proposal and updated navigation acceptance scope 2026-09-11 12:08:32 -07:00
sorokin.oleg.edu 2dedde29e9 Preserve initial navigation native trial and confirmed interaction defects 2026-09-11 12:07:30 -07:00
sorokin.oleg.edu 8e00d3ce4f Record matching navigation GUI build and focused coordination entrypoints 2026-09-11 11:34:00 -07:00
sorokin.oleg.edu 36db9356cc Add bounded definition and reference navigation for current source drafts
Preserve loaded draft bytes and model history, reject stale workspace and input events, and keep captured Escape under modal priority. Verified 181 focused Windows tests and strict desktop Clippy on exact inputs4; earlier full737 scope and component/native preparation evidence are archived separately. Native navigation acceptance remains pending.
2026-09-11 11:23:20 -07:00
sorokin.oleg.edu fb24def2f5 Record verified contextual Windows prerelease and Gitea handoff 2026-09-11 10:14:53 -07:00
sorokin.oleg.edu b70bf1df45 Sync agent instructions from main 2026-09-11 19:52:14 +03:00
1287 changed files with 293615 additions and 18924 deletions
+16 -13
View File
@@ -65,16 +65,19 @@ harness/experiments/contextual-source-machine-v2-20260911/**/*.arcadia whitespac
harness/experiments/contextual-source-reopen-20260911/launch-method.ps1 whitespace=-blank-at-eof,cr-at-eol
# Raw compact.exe output includes CR-CR-LF and incidental trailing spaces.
harness/experiments/wsl-capacity-20260911/*.log -whitespace
# Preserve exact frozen GUI5657 contextual milestone input bytes.
crates/oa-desktop/src/behavior/creation.rs -text
crates/oa-desktop/src/behavior/scenario/workspace.rs -text
crates/oa-desktop/src/behavior/topology/contextual.rs -text
crates/oa-desktop/src/guide.rs -text
crates/oa-desktop/src/semantic_review/artifacts_view.rs -text
crates/oa-desktop/src/semantic_review/attachments_view.rs -text
crates/oa-desktop/src/semantic_review/keyed_rows.rs -text
crates/oa-desktop/src/semantic_review/keyed_tests.rs -text
crates/oa-desktop/src/semantic_review/keyed.rs -text
crates/oa-desktop/src/semantic_review/ordered.rs -text
docs/openapi.json -text
harness/experiments/contextual-prerelease-20260911/** -text whitespace=cr-at-eol
harness/experiments/contextual-prerelease-publication-20260911/** -text whitespace=cr-at-eol
harness/history/2026-09-11-state-before-gitea-migration/** -text whitespace=cr-at-eol
harness/experiments/contextual-prerelease-20260911/native/**/*.arcadia whitespace=-blank-at-eol,-blank-at-eof,cr-at-eol
harness/experiments/contextual-prerelease-20260911/producer/package*.log whitespace=-blank-at-eof,cr-at-eol
harness/experiments/contextual-prerelease-20260911/producer/source-push.log -whitespace
harness/experiments/source-alias-rename-native-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-completed-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-refresh-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-native-closure-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-scroll-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-server-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-package-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-packaged-runtime-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-package-native-20260912/** -text whitespace=cr-at-eol
harness/experiments/source-alias-rename-publication-20260912/** -text whitespace=cr-at-eol
+160 -27
View File
@@ -142,12 +142,87 @@ pub struct Analysis {
pub declarations: Vec<DeclarationSpan>,
}
/// Check the decoded spelling required by declaration-header UUID clauses.
/// This is the shared 36-byte/hyphen shape rule, not a hexadecimal parser:
/// callers must additionally parse the UUID. Uppercase hex and JSON escapes
/// that decode to this spelling remain accepted. URN/braced/compact forms do not.
pub fn has_uuid_header_shape(decoded: &str) -> bool {
decoded.len() == 36
&& [8, 13, 18, 23]
.into_iter()
.all(|index| decoded.as_bytes()[index] == b'-')
}
/// Budgets for one original source buffer. Policy is caller-owned; these
/// limits do not change the grammar or perform model admission.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OutlineLimits {
pub max_source_bytes: usize,
pub max_tokens: usize,
pub max_declarations: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OutlineResource {
SourceBytes,
Tokens,
Declarations,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OutlineLimit {
pub resource: OutlineResource,
pub limit: usize,
pub observed_at_least: usize,
/// Original byte offset where admission stopped; never a rewritten offset.
pub offset: usize,
}
/// Roles discovered by the existing tolerant declaration walk. Keeping the
/// wrapper preserves DeclarationSpan and Analysis as existing public APIs.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OutlineDeclaration {
pub declaration: DeclarationSpan,
pub kind_span: Span,
pub alias_span: Span,
/// Whole quoted header ID token, even if it is not a valid UUID. In that
/// case declaration.id is None. Missing/non-string ID values have no span.
pub id_literal_span: Option<Span>,
}
/// A full-file tolerant scan, not a successful parse or validated model. Invalid
/// text remains available. Lexical errors and unmatched braces are facts only:
/// their absence does not establish syntactic or semantic validity.
///
/// A budget failure returns Err and no partial Outline. Include reachability,
/// project completeness and editor revision are intentionally not inferred here.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Outline<'a> {
pub source: &'a str,
pub tokens: Vec<TokenSpan>,
pub declarations: Vec<OutlineDeclaration>,
pub has_lexical_errors: bool,
pub has_unmatched_braces: bool,
}
/// Tolerant highlighting tokens cover the whole input, including incomplete
/// strings and unexpected characters. No model is created or modified.
pub fn tokenize(source: &str) -> Vec<TokenSpan> {
tokenize_with_limit(source, usize::MAX).expect("unlimited token scan")
}
fn tokenize_with_limit(source: &str, max_tokens: usize) -> Result<Vec<TokenSpan>, OutlineLimit> {
let mut tokens = Vec::new();
let mut cursor = 0;
while cursor < source.len() {
if tokens.len() == max_tokens {
return Err(OutlineLimit {
resource: OutlineResource::Tokens,
limit: max_tokens,
observed_at_least: tokens.len().saturating_add(1),
offset: cursor,
});
}
let start = cursor;
let ch = source[cursor..].chars().next().expect("in bounds");
let class = if matches!(ch, ' ' | '\t' | '\r' | '\n') {
@@ -224,7 +299,7 @@ pub fn tokenize(source: &str) -> Vec<TokenSpan> {
span: Span { start, end: cursor },
});
}
tokens
Ok(tokens)
}
pub fn lint(source: &str) -> Vec<Diagnostic> {
@@ -1230,11 +1305,7 @@ impl Parser<'_> {
self.cursor += 1;
let offset = self.current().span.start;
let value = self.quoted()?;
if value.len() != 36
|| ![8, 13, 18, 23]
.into_iter()
.all(|i| value.as_bytes()[i] == b'-')
{
if !has_uuid_header_shape(&value) {
return Err(Error {
code: "invalid_source",
offset,
@@ -1962,8 +2033,49 @@ fn take_required_id(fields: &mut Map<String, Value>, key: &str) -> Result<Id, St
/// Analyze an incomplete source buffer without adopting a candidate. Declaration
/// spans remain available even when a later declaration contains errors.
/// Invalid compact/braced/URN header IDs retain no authored identity, matching
/// the declaration parser rather than the UUID crate's broader accepted forms.
pub fn analyze(source: &str) -> Analysis {
let tokens = tokenize(source);
let (declarations, _) =
declaration_outline(source, &tokens, usize::MAX).expect("unlimited declaration walk");
Analysis {
tokens,
diagnostics: lint(source),
declarations: declarations.into_iter().map(|d| d.declaration).collect(),
}
}
/// Read exact current text without lint, parsing a model, stabilization or I/O.
/// Source bytes are admitted before token allocation; token/declaration limits
/// are checked before lexing the next token or materializing the next record.
pub fn outline(source: &str, limits: OutlineLimits) -> Result<Outline<'_>, OutlineLimit> {
if source.len() > limits.max_source_bytes {
return Err(OutlineLimit {
resource: OutlineResource::SourceBytes,
limit: limits.max_source_bytes,
observed_at_least: source.len(),
offset: 0,
});
}
let tokens = tokenize_with_limit(source, limits.max_tokens)?;
let has_lexical_errors = tokens.iter().any(|token| token.class == TokenClass::Error);
let (declarations, has_unmatched_braces) =
declaration_outline(source, &tokens, limits.max_declarations)?;
Ok(Outline {
source,
tokens,
declarations,
has_lexical_errors,
has_unmatched_braces,
})
}
fn declaration_outline(
source: &str,
tokens: &[TokenSpan],
max_declarations: usize,
) -> Result<(Vec<OutlineDeclaration>, bool), OutlineLimit> {
let significant = tokens
.iter()
.filter(|t| !matches!(t.class, TokenClass::Whitespace | TokenClass::Comment))
@@ -1972,17 +2084,21 @@ pub fn analyze(source: &str) -> Analysis {
// again would make tolerant navigation quadratic on deeply nested drafts.
let mut body_ends = vec![None; significant.len()];
let mut bodies = Vec::new();
let mut unmatched_close = false;
for (index, token) in significant.iter().enumerate() {
match &source[token.span.start..token.span.end] {
"{" => bodies.push(index),
"}" => {
if let Some(open) = bodies.pop() {
body_ends[open] = Some(token.span.end);
} else {
unmatched_close = true;
}
}
_ => {}
}
}
let has_unmatched_braces = unmatched_close || !bodies.is_empty();
let mut declarations = Vec::new();
for (i, t) in significant.iter().enumerate() {
let word = &source[t.span.start..t.span.end];
@@ -2007,7 +2123,16 @@ pub fn analyze(source: &str) -> Analysis {
}
j += 1;
}
if declarations.len() == max_declarations {
return Err(OutlineLimit {
resource: OutlineResource::Declarations,
limit: max_declarations,
observed_at_least: declarations.len().saturating_add(1),
offset: t.span.start,
});
}
let mut id = None;
let mut id_literal_span = None;
if significant
.get(j)
.is_some_and(|t| &source[t.span.start..t.span.end] == "id")
@@ -2015,39 +2140,51 @@ pub fn analyze(source: &str) -> Analysis {
if let Some(value) = significant.get(j + 1)
&& value.class == TokenClass::String
{
id_literal_span = Some(value.span);
let text =
serde_json::from_str::<String>(&source[value.span.start..value.span.end])
.unwrap();
id = Id::parse_str(&text).ok();
if has_uuid_header_shape(&text) {
id = Id::parse_str(&text).ok();
}
}
j += 2;
}
let mut end = significant
.get(j)
.map_or(alias_token.span.end, |t| t.span.end);
// A recognized header ID at EOF must remain inside the whole span.
// Keep the old next-token/body behavior; only the EOF fallback changes.
let header_end = significant
.get(j.saturating_sub(1))
.or_else(|| significant.last())
.map_or(alias_token.span.end, |token| token.span.end);
let mut end = significant.get(j).map_or(header_end, |t| t.span.end);
if significant
.get(j)
.is_some_and(|t| &source[t.span.start..t.span.end] == "{")
{
end = body_ends[j].unwrap_or(source.len());
}
declarations.push(DeclarationSpan {
alias: alias.into(),
id,
kind: word.into(),
span: Span {
start: t.span.start,
end,
declarations.push(OutlineDeclaration {
declaration: DeclarationSpan {
alias: alias.into(),
id,
kind: word.into(),
span: Span {
start: t.span.start,
end,
},
},
kind_span: t.span,
alias_span: alias_token.span,
id_literal_span,
});
}
Analysis {
tokens,
diagnostics: lint(source),
declarations,
}
Ok((declarations, has_unmatched_braces))
}
#[cfg(test)]
#[path = "language_outline_tests.rs"]
mod outline_tests;
#[cfg(test)]
#[path = "language_nesting_tests.rs"]
mod nesting_tests;
@@ -2442,11 +2579,7 @@ pub(crate) mod legacy {
let value = self.quoted()?;
// Require the portable 8-4-4-4-12 spelling, not the UUID crate's URN,
// braces, or compact alternatives. Uppercase hexadecimal is accepted.
if value.len() != 36
|| ![8, 13, 18, 23]
.into_iter()
.all(|index| value.as_bytes()[index] == b'-')
{
if !super::has_uuid_header_shape(&value) {
return Err(Error {
code: "invalid_source",
offset,
@@ -0,0 +1,386 @@
//! Prepared outline tests. Explicit compatibility tests additionally exercise
//! the existing parsers/analyze; the outline entry itself never calls them.
use super::*;
fn limits() -> OutlineLimits {
OutlineLimits {
max_source_bytes: 1024 * 1024,
max_tokens: 100_000,
max_declarations: 1_000,
}
}
fn declaration<'a>(result: &'a Outline<'_>, alias: &str) -> &'a OutlineDeclaration {
result
.declarations
.iter()
.find(|d| d.declaration.alias == alias)
.unwrap()
}
fn text(source: &str, span: Span) -> &str {
&source[span.start..span.end]
}
#[test]
fn outline_roles_preserve_unicode_crlf_and_exact_escaped_uuid_literal() {
let source = "// 検査 🚒\r\noa_actor responder \"救助\" id \"\\u00300000000-0000-0000-0000-000000000001\" {}\r\nsource @ // 使用\r\n responder;";
let before = source.as_bytes().to_vec();
let result = outline(source, limits()).unwrap();
assert_eq!(result.source.as_bytes(), before);
assert_eq!(result.source.as_ptr(), source.as_ptr());
let d = declaration(&result, "responder");
assert_eq!(text(source, d.kind_span), "oa_actor");
assert_eq!(text(source, d.alias_span), "responder");
assert_eq!(
text(source, d.id_literal_span.unwrap()),
"\"\\u00300000000-0000-0000-0000-000000000001\""
);
assert_eq!(d.declaration.id, Some(Id::from_u128(1)));
assert_eq!(d.declaration.span.start, source.find("oa_actor").unwrap());
assert_eq!(d.declaration.span.end, source.find("{}\r\n").unwrap() + 2);
let mut end = 0;
for token in &result.tokens {
assert_eq!(token.span.start, end);
assert!(token.span.start < token.span.end);
assert!(source.is_char_boundary(token.span.start));
assert!(source.is_char_boundary(token.span.end));
end = token.span.end;
}
assert_eq!(end, source.len());
assert!(!result.has_lexical_errors);
assert!(!result.has_unmatched_braces);
}
#[test]
fn closed_id_at_eof_is_inside_the_declaration_extent() {
for source in [
"oa_actor a \"Actor\" id \"00000000-0000-0000-0000-000000000001\"",
"node placed id \"00000000-0000-0000-0000-000000000001\"",
] {
let result = outline(source, limits()).unwrap();
let d = &result.declarations[0];
let literal = d.id_literal_span.unwrap();
assert_eq!(d.declaration.id, Some(Id::from_u128(1)));
assert_eq!(d.declaration.span.end, source.len());
assert!(d.declaration.span.start <= literal.start);
assert!(literal.end <= d.declaration.span.end);
}
for source in ["oa_actor a \"Actor\"", "oa_actor a \"Actor\" id"] {
let result = outline(source, limits()).unwrap();
let d = &result.declarations[0];
assert_eq!(d.declaration.span.end, source.len());
assert_eq!(d.declaration.id, None);
assert_eq!(d.id_literal_span, None);
}
}
#[test]
fn missing_bad_and_historical_ids_never_allocate_authored_identity() {
let source = "oa_actor missing \"No ID\" {}\noa_actor bad \"Bad ID\" id \"not-a-uuid\" {}\noa_actor historical \"00000000-0000-0000-0000-000000000001\" { history uuid \"00000000-0000-0000-0000-000000000001\"; }";
let first = outline(source, limits()).unwrap();
let second = outline(source, limits()).unwrap();
assert_eq!(first, second);
assert!(
first
.declarations
.iter()
.all(|d| d.declaration.id.is_none())
);
assert_eq!(declaration(&first, "missing").id_literal_span, None);
assert_eq!(declaration(&first, "historical").id_literal_span, None);
assert_eq!(
text(source, declaration(&first, "bad").id_literal_span.unwrap()),
"\"not-a-uuid\""
);
// Balanced tokens are not a successful syntax/semantic validation claim.
assert!(!first.has_lexical_errors);
assert!(!first.has_unmatched_braces);
}
#[test]
fn invalid_full_scan_keeps_closed_children_and_reports_lexical_body_facts() {
let source = "oa_entity outer \"Outer\" {\n oa_actor ready \"Ready\" { description \"} stays text\"; }\n oa_actor pending \"Pending\" { description \"unfinished 🌊";
let result = outline(source, limits()).unwrap();
assert_eq!(result.source, source);
assert_eq!(result.tokens.last().unwrap().span.end, source.len());
assert!(result.has_lexical_errors);
assert!(result.has_unmatched_braces);
let ready = declaration(&result, "ready");
assert_eq!(
text(source, ready.declaration.span),
"oa_actor ready \"Ready\" { description \"} stays text\"; }"
);
assert_eq!(
declaration(&result, "outer").declaration.span.end,
source.len()
);
assert_eq!(
declaration(&result, "pending").declaration.span.end,
source.len()
);
let unmatched_close = outline("}\n// brace in comment {\n", limits()).unwrap();
assert!(unmatched_close.has_unmatched_braces);
assert!(!unmatched_close.has_lexical_errors);
}
#[test]
fn missing_body_syntax_is_unchecked_even_when_known_error_flags_are_clear() {
let source = "oa_actor a \"A\" id \"00000000-0000-0000-0000-000000000001\"";
let result = outline(source, limits()).unwrap();
assert_eq!(result.declarations.len(), 1);
assert!(!result.has_lexical_errors);
assert!(!result.has_unmatched_braces);
// There is deliberately no `valid` flag: the known-complete fact is scanning
// these bytes, not the missing body becoming legal or the draft being applied.
assert_eq!(result.source, source);
}
#[test]
fn keyword_alias_and_collisions_keep_every_source_ordered_header() {
let source = "project root_model \"Model\" {\n oa_actor oa_activity \"First\" id \"00000000-0000-0000-0000-000000000001\" {}\n oa_actor oa_activity \"Second\" id \"00000000-0000-0000-0000-000000000001\" {}\n diagram view_one \"View\" {}\n node placement { diagram @view_one; }\n}";
let result = outline(source, limits()).unwrap();
assert_eq!(result.declarations.len(), 5);
let duplicates: Vec<_> = result
.declarations
.iter()
.filter(|d| d.declaration.alias == "oa_activity")
.collect();
assert_eq!(duplicates.len(), 2);
assert!(duplicates[0].alias_span.start < duplicates[1].alias_span.start);
assert_eq!(duplicates[0].declaration.id, duplicates[1].declaration.id);
assert!(
result
.tokens
.iter()
.any(|t| t.span == duplicates[0].alias_span && t.class == TokenClass::Keyword)
);
assert_eq!(
text(source, declaration(&result, "placement").kind_span),
"node"
);
assert_eq!(declaration(&result, "placement").declaration.id, None);
}
#[test]
fn bounds_refuse_before_returning_a_partial_outline() {
let source = "oa_actor a \"A\" {}\noa_actor b \"B\" {}";
let admitted = outline(source, limits()).unwrap();
let exact = OutlineLimits {
max_source_bytes: source.len(),
max_tokens: admitted.tokens.len(),
max_declarations: 2,
};
assert_eq!(outline(source, exact).unwrap(), admitted);
for resource in [
OutlineResource::SourceBytes,
OutlineResource::Tokens,
OutlineResource::Declarations,
] {
let mut lower = exact;
match resource {
OutlineResource::SourceBytes => lower.max_source_bytes -= 1,
OutlineResource::Tokens => lower.max_tokens -= 1,
OutlineResource::Declarations => lower.max_declarations -= 1,
}
let error = outline(source, lower).unwrap_err();
assert_eq!(error.resource, resource);
assert!(error.observed_at_least > error.limit);
assert!(source.is_char_boundary(error.offset));
if resource == OutlineResource::Declarations {
assert_eq!(error.offset, source.find("oa_actor b").unwrap());
}
}
let empty = outline(
"",
OutlineLimits {
max_source_bytes: 0,
max_tokens: 0,
max_declarations: 0,
},
)
.unwrap();
assert!(empty.tokens.is_empty() && empty.declarations.is_empty());
let unicode = "// 🌊\r\noa_actor a \"A\" {}";
let error = outline(
unicode,
OutlineLimits {
max_source_bytes: 4,
..limits()
},
)
.unwrap_err();
assert_eq!(error.resource, OutlineResource::SourceBytes);
assert_eq!(error.offset, 0);
let error = outline(
unicode,
OutlineLimits {
max_tokens: 1,
..limits()
},
)
.unwrap_err();
assert_eq!(error.resource, OutlineResource::Tokens);
assert_eq!(error.offset, unicode.find('\n').unwrap());
}
#[test]
fn outline_ranges_follow_current_bytes_without_identity_stabilization() {
let old = "oa_actor a \"A\" {}\nsource @a;";
let current = format!("// 航海 🚒\r\n{old}");
let old_outline = outline(old, limits()).unwrap();
let current_outline = outline(&current, limits()).unwrap();
let shift = current.len() - old.len();
let old_role = &old_outline.declarations[0];
let current_role = &current_outline.declarations[0];
assert_eq!(
current_role.alias_span.start,
old_role.alias_span.start + shift
);
assert_eq!(
current_role.kind_span.start,
old_role.kind_span.start + shift
);
assert_eq!(
current_role.declaration.span.end,
old_role.declaration.span.end + shift
);
assert_eq!(current_outline.source, current);
assert_eq!(old_outline.source, old);
assert_eq!(current_role.declaration.id, None);
assert!(!current_outline.source.contains(" id "));
// Workspace revision/stale-handle rejection belongs to the query/adapter,
// not a claim that an old owned span can be applied to any other string.
}
#[test]
fn deeply_nested_bounds_use_the_same_iterative_walk_and_declaration_budget() {
let mut source = String::new();
for index in 0..600 {
source.push_str(&format!("oa_activity work_{index} \"Work\" {{\n"));
}
source.push_str(&"}\n".repeat(600));
let result = outline(&source, limits()).unwrap();
assert_eq!(result.declarations.len(), 600);
assert!(!result.has_unmatched_braces);
assert_eq!(
result.declarations[0].declaration.span.end,
source.len() - 1
);
let error = outline(
&source,
OutlineLimits {
max_declarations: 599,
..limits()
},
)
.unwrap_err();
assert_eq!(error.resource, OutlineResource::Declarations);
assert_eq!(error.observed_at_least, 600);
assert_eq!(error.offset, source.find("oa_activity work_599").unwrap());
}
#[test]
fn noncanonical_uuid_spellings_have_no_outline_or_analysis_identity() {
for raw in [
"00000000000000000000000000000001",
"{00000000-0000-0000-0000-000000000001}",
"urn:uuid:00000000-0000-0000-0000-000000000001",
] {
assert!(
Id::parse_str(raw).is_ok(),
"The UUID crate alone is too permissive"
);
assert!(!has_uuid_header_shape(raw));
let literal = format!("\"{raw}\"");
let modern = format!("arcadia 7; project model \"Model\" id {literal} {{}}");
let before = modern.clone();
let result = outline(&modern, limits()).unwrap();
let d = declaration(&result, "model");
assert_eq!(d.declaration.id, None);
assert_eq!(text(&modern, d.id_literal_span.unwrap()), literal);
assert_eq!(modern, before);
let errors = parse(&modern).unwrap_err();
assert!(
errors
.iter()
.any(|error| error.message.contains("8-4-4-4-12")
&& error.span.start == modern.find(&literal).unwrap())
);
// Intentional compatibility correction: old analyze yielded Some(Id(1))
// here despite lint rejecting the header. It now shares outline's None.
let analysis = analyze(&modern);
assert_eq!(
analysis
.declarations
.iter()
.find(|d| d.alias == "model")
.unwrap()
.id,
None
);
assert!(
analysis
.diagnostics
.iter()
.any(|error| error.message.contains("8-4-4-4-12"))
);
let legacy_source = format!("arcadia 1; project \"Legacy\" id {literal} {{}}");
let legacy_errors = legacy::parse(&legacy_source).unwrap_err();
assert!(
legacy_errors
.iter()
.any(|error| error.message.contains("8-4-4-4-12"))
);
}
}
#[test]
fn uppercase_and_json_escaped_header_ids_survive_both_parsers_and_outline() {
let expected = Id::from_u128(0xabcdef);
let canonical = expected.to_string();
let uppercase = canonical.to_uppercase();
assert_ne!(uppercase, canonical);
for raw in [uppercase.clone(), format!("\\u0030{}", &uppercase[1..])] {
let literal = format!("\"{raw}\"");
let decoded: String = serde_json::from_str(&literal).unwrap();
assert!(has_uuid_header_shape(&decoded));
let modern = format!("arcadia 7; project model \"Model\" id {literal} {{}}");
let result = outline(&modern, limits()).unwrap();
let d = declaration(&result, "model");
assert_eq!(d.declaration.id, Some(expected));
assert_eq!(text(&modern, d.id_literal_span.unwrap()), literal);
assert_eq!(result.source.as_bytes(), modern.as_bytes());
assert_eq!(parse(&modern).unwrap().id, expected);
let analysis = analyze(&modern);
assert_eq!(analysis.declarations[0].id, Some(expected));
assert!(
!analysis
.diagnostics
.iter()
.any(|error| error.severity == crate::validation::Severity::Error)
);
let legacy_source = format!("arcadia 1; project \"Legacy\" id {literal} {{}}");
assert_eq!(legacy::parse(&legacy_source).unwrap().id, expected);
}
}
#[test]
fn header_shape_still_requires_valid_hexadecimal_uuid_data() {
let raw = "00000000-0000-0000-0000-00000000000Z";
assert!(has_uuid_header_shape(raw));
assert!(Id::parse_str(raw).is_err());
let literal = format!("\"{raw}\"");
let source = format!("arcadia 7; project model \"Model\" id {literal} {{}}");
let result = outline(&source, limits()).unwrap();
let d = declaration(&result, "model");
assert_eq!(d.declaration.id, None);
assert_eq!(text(&source, d.id_literal_span.unwrap()), literal);
assert!(
parse(&source)
.unwrap_err()
.iter()
.any(|error| error.message == "Invalid UUID identity.")
);
assert_eq!(analyze(&source).declarations[0].id, None);
}
+180 -26
View File
@@ -7,6 +7,8 @@ mod diagram_selection_tests;
mod hosted;
#[cfg(test)]
mod review_navigation_tests;
pub(crate) mod source_rename;
mod source_symbols;
#[cfg(test)]
mod transition_context_tests;
#[cfg(test)]
@@ -415,9 +417,17 @@ pub enum Message {
Linted(u64, Result<Vec<SourceDiagnostic>, String>),
SourceDiagnostic(usize),
SourceRelated(SourceLocation),
SourceViewport,
SourceViewport(Option<Id>),
SourceSymbols(
crate::source_navigation::SymbolContext,
crate::source_navigation::SymbolEvent,
),
SourceSymbolsReady(crate::source_navigation::Completion),
SourceRename(source_rename::Event),
SourceRenameReady(source_rename::Completion),
SourceForSelection,
SourceNavigation(crate::source_navigation::Event),
SourceFindClose(crate::source_navigation::SymbolContext, Id),
Save(bool),
SavePath(Option<PathBuf>),
Saved(Result<Option<FileSnapshot>, SaveFailure>),
@@ -491,6 +501,9 @@ pub struct App {
pub source_jump: Option<text_editor::Cursor>,
source_select_line: bool,
pub source_navigation: crate::source_navigation::State,
source_find_instance: Id,
pub source_symbols: crate::source_navigation::SymbolState,
pub source_rename: source_rename::State,
pub model_issues: Vec<validation::Issue>,
pub migration: Option<persistence::MigrationReport>,
source_version: u64,
@@ -596,6 +609,9 @@ impl App {
source_jump: None,
source_select_line: false,
source_navigation: crate::source_navigation::State::default(),
source_find_instance: Id::new_v4(),
source_symbols: crate::source_navigation::SymbolState::default(),
source_rename: source_rename::State::default(),
model_issues,
migration: None,
source_version: 0,
@@ -642,18 +658,37 @@ impl App {
|| self.behavior.has_pending()
}
fn sync_source(&mut self) {
self.sync_source_with_alias_editor(None);
}
fn sync_source_with_alias_editor(&mut self, hint: Option<source_rename::EditorRefresh<'_>>) {
self.source_workspace.accept(self.document.bundle());
self.show_source_file(false);
self.show_source_file_with_alias_editor(false, hint);
self.source_diagnostics = self.document.compiled().diagnostics.clone();
self.source_version += 1;
self.lint_requested = None;
}
fn show_source_file(&mut self, restore_cursor: bool) {
self.show_source_file_with_alias_editor(restore_cursor, None);
}
fn show_source_file_with_alias_editor(
&mut self,
restore_cursor: bool,
hint: Option<source_rename::EditorRefresh<'_>>,
) {
self.source_symbols.reveal = None;
self.source_tree.reveal(&self.source_workspace.active);
self.source_select_line = false;
let source = self.source_workspace.text().to_owned();
self.source_navigation.refresh(&source);
self.source_editor = text_editor::Content::with_text(&source);
if !hint.is_some_and(|hint| {
hint.apply(
&mut self.source_editor,
&self.source_workspace.active,
&source,
)
}) {
self.source_editor = text_editor::Content::with_text(&source);
}
self.source_snapshot = Arc::from(source);
self.source_jump = restore_cursor
.then(|| {
@@ -663,6 +698,9 @@ impl App {
.map(|b| b.cursor)
})
.flatten();
if let Some(cursor) = self.source_jump {
self.queue_source_reveal(cursor, false);
}
}
fn selected_architecture_placement(&self) -> Option<Id> {
self.active_diagram
@@ -695,6 +733,9 @@ impl App {
}
}
fn sync(&mut self) {
self.sync_with_alias_editor(None);
}
fn sync_with_alias_editor(&mut self, hint: Option<source_rename::EditorRefresh<'_>>) {
self.explorer_index = crate::explorer::Index::new(self.project(), self.layer);
self.model_issues = validate(self.project());
self.normalize_creation();
@@ -724,7 +765,7 @@ impl App {
.map(|d| d.id);
}
self.refresh_draft();
self.sync_source();
self.sync_source_with_alias_editor(hint);
}
fn normalize_creation(&mut self) {
if !self.create_kind.supports(self.layer) {
@@ -916,6 +957,8 @@ impl App {
let canvas_size = self.canvas_size;
let source_version = self.source_version + 1;
let lint_running = self.lint_running;
let navigation_in_flight = self.source_symbols.in_flight;
let rename_in_flight = self.source_rename.in_flight;
let guide = std::mem::take(&mut self.guide);
let mut hosted = std::mem::take(&mut self.hosted);
hosted.leave_document();
@@ -927,6 +970,8 @@ impl App {
self.canvas_size = canvas_size;
self.source_version = source_version;
self.lint_running = lint_running;
self.source_symbols.in_flight = navigation_in_flight;
self.source_rename.in_flight = rename_in_flight;
self.guide = guide;
self.path = path;
self.status = "Project ready".into();
@@ -1027,7 +1072,10 @@ impl App {
crate::model_menu::popup(self),
)
.into();
crate::hosted::view::overlay(self, base)
crate::source_navigation::interaction::observe(
crate::hosted::view::overlay(self, base),
self.source_symbols.raw_interaction.clone(),
)
}
pub fn subscription(&self) -> Subscription<Message> {
Subscription::batch([
@@ -1035,8 +1083,16 @@ impl App {
window::close_requests().map(|id| Message::Request(Pending::Close(id))),
window::resize_events().map(|(_, size)| Message::WindowResized(size)),
architecture_authoring::subscription(self),
// Use one captured-Escape bridge: a focused Find input consumes
// Escape, while modal priority remains in the ordinary handler.
behavior::creation::subscription(
self.behavior.creation.has_pending() || self.behavior.source_active(),
self.behavior.creation.has_pending()
|| self.behavior.source_active()
|| (self.page == Page::Text
&& (self.source_symbols.open
|| self.source_navigation.open
|| self.source_rename.open())
&& self.architecture.is_none()),
)
.map(|()| Message::Escape),
iced::event::listen_with(|event, status, _| {
@@ -1083,6 +1139,55 @@ impl App {
])
}
pub fn update(&mut self, message: Message) -> Task<Message> {
if let Message::SourceRename(event) = &message
&& !self.source_rename_envelope(event)
{
return Task::none();
}
let message = match message {
Message::SourceFindClose(context, instance) => {
if context != self.source_symbol_context()
|| instance != self.source_find_instance
|| !self.source_navigation.open
|| !self.source_navigation_available()
{
return Task::none();
}
// Only the checked envelope may enter the legacy Close handler.
Message::SourceNavigation(crate::source_navigation::Event::Close)
}
Message::SourceNavigation(crate::source_navigation::Event::Close) => {
return Task::none();
}
message => message,
};
if let Message::SourceSymbols(context, _) = &message
&& (context.session != self.source_workspace.session()
|| context.path != self.source_workspace.active)
{
return Task::none();
}
// Internal results and geometry do not constitute a new user intent.
// Process query completion even behind a modal to release its worker slot;
// its handler independently refuses navigation outside the live editor.
if let Message::SourceSymbolsReady(completion) = message {
return self.source_symbols_ready(completion);
}
if let Message::SourceRenameReady(completion) = message {
return self.source_rename_ready(completion);
}
if !matches!(
&message,
Message::CheckpointTick
| Message::CheckpointWritten(..)
| Message::Lint(_)
| Message::Linted(..)
| Message::SourceViewport(_)
| Message::WindowResized(_)
| Message::CanvasResized(_)
) {
self.source_interaction();
}
if matches!(&message, Message::Connection(_))
&& self
.architecture
@@ -1147,7 +1252,7 @@ impl App {
| Message::CanvasResized(_)
| Message::Lint(_)
| Message::Linted(_, _)
| Message::SourceViewport
| Message::SourceViewport(_)
| Message::Request(Pending::Close(_))
)
{
@@ -1193,7 +1298,7 @@ impl App {
| Message::Exported(_)
| Message::WindowResized(_)
| Message::CanvasResized(_)
| Message::SourceViewport
| Message::SourceViewport(_)
)
{
return Task::none();
@@ -1231,7 +1336,7 @@ impl App {
| Message::CheckpointLoaded(..)
| Message::WindowResized(_)
| Message::CanvasResized(_)
| Message::SourceViewport
| Message::SourceViewport(_)
| Message::Lint(_)
| Message::Linted(_, _)
| Message::Saved(_)
@@ -1261,6 +1366,18 @@ impl App {
{
return Task::none();
}
if self.source_rename.open() {
if matches!(
message,
Message::Escape | Message::Request(Pending::Close(_))
) {
self.close_source_rename();
return Task::none();
}
if !modal_event && !matches!(message, Message::SourceRename(_)) {
return Task::none();
}
}
if matches!(
message,
Message::Page(_) | Message::Layer(_) | Message::Diagram(_)
@@ -1305,6 +1422,7 @@ impl App {
self.last_workspace_page = self.page;
}
let mut task = self.handle(message);
self.refresh_source_rename_context();
self.route_state_diagram_workspace();
if self.page != Page::Home {
self.last_workspace_page = self.page;
@@ -1791,6 +1909,8 @@ impl App {
return self.update(Message::Add(child));
}
Message::Escape => {
let restore_source_focus = self.source_navigation_available()
&& (self.source_navigation.open || self.source_symbols.open);
if self.behavior.source_back() {
self.status =
"Returned to the unchanged parent form; no source was created.".into();
@@ -1807,6 +1927,12 @@ impl App {
self.status = "Drawing cancelled · Select / move is active".into();
}
self.source_navigation.open = false;
self.source_symbols.open = false;
self.source_symbols.results = None;
self.source_symbols.notice = None;
if restore_source_focus {
self.restore_source_editor_focus();
}
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
self.selected_bend = None;
}
@@ -2842,6 +2968,7 @@ impl App {
if self.pending_recovery.as_ref() != Some(&receipt.target) {
return Task::none();
}
self.invalidate_source_rename("Disk recovery changed this source context. Your replacement is retained; close and invoke Rename again.");
self.pending_recovery = None;
self.source_diagnostics
.retain(|issue| issue.diagnostic.code != "pending_save");
@@ -2855,12 +2982,21 @@ impl App {
if self.path.is_none()
|| self.path.as_ref() == Some(&receipt.target)
{
if self.path.as_ref() != Some(&receipt.target) {
self.source_workspace.reset_navigation_session();
}
self.path = Some(receipt.target);
self.document.bind_repair_baseline(disk.reachable_bundle());
self.disk_project = Some(disk);
}
self.status = "Interrupted disk save recovered. Current model and drafts are retained; Save all can be retried.".into();
}
Err(error) => {
if self.path.is_none()
|| self.path.as_ref() == Some(&receipt.target)
{
self.document.invalidate_saved_baseline();
}
self.status = format!(
"Disk recovery completed; files could not be reloaded: {error}"
)
@@ -2917,14 +3053,13 @@ impl App {
}
}
Message::SourceRelated(location) => self.jump_to_source(location),
Message::SourceViewport => {
if let Some(cursor) = self.source_jump.take() {
self.source_editor.move_to(cursor);
if self.source_select_line && cursor.selection.is_none() {
self.source_editor.perform(text_editor::Action::SelectLine);
}
return iced::widget::operation::focus("source-editor");
}
Message::SourceViewport(ticket) => return self.source_viewport(ticket),
Message::SourceFindClose(..) => return Task::none(), // update checks and unwraps it
Message::SourceSymbols(_, event) => return self.source_symbol_event(event),
Message::SourceRename(event) => return self.source_rename_event(event),
Message::SourceRenameReady(completion) => return self.source_rename_ready(completion),
Message::SourceSymbolsReady(completion) => {
return self.source_symbols_ready(completion);
}
Message::ApplySource => {
self.apply_source();
@@ -2970,6 +3105,7 @@ impl App {
return Task::none();
}
self.page = Page::Text;
self.source_find_instance = Id::new_v4();
self.source_navigation.open = true;
self.source_navigation.refresh(&self.source_editor.text());
return iced::widget::operation::focus(if go_to_line {
@@ -2978,13 +3114,22 @@ impl App {
"source-find"
});
}
Event::Close => self.source_navigation.open = false,
Event::Close => {
let was_open = self.source_navigation.open;
self.source_navigation.open = false;
if was_open {
self.restore_source_editor_focus();
}
}
Event::Query(query) => {
self.source_navigation.query = query;
self.source_navigation.refresh(&self.source_editor.text());
}
Event::Next(backwards) if self.page == Page::Text => {
self.source_jump = self.source_navigation.next(backwards);
if let Some(cursor) = self.source_jump {
self.queue_source_reveal(cursor, false);
}
if self.source_jump.is_none() {
self.status = "No matching source text.".into();
}
@@ -2995,8 +3140,7 @@ impl App {
.destination(self.source_editor.line_count())
{
Ok(cursor) => {
self.source_jump = Some(cursor);
self.source_select_line = true;
self.queue_source_reveal(cursor, true);
}
Err(error) => self.status = error,
},
@@ -3079,6 +3223,9 @@ impl App {
}
self.sync_source();
}
if self.path.as_ref() != Some(&receipt.path) {
self.source_workspace.reset_navigation_session();
}
self.disk_project = Some(disk);
self.path = Some(receipt.path);
self.hosted.session = None;
@@ -3637,8 +3784,9 @@ impl App {
self.canvas_document = Id::new_v4();
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
self.path = Some(path);
self.document.bind_repair_baseline(disk.reachable_bundle());
self.source_workspace = Workspace::new(&disk.bundle, false);
self.source_workspace.reachable = disk.reachable.clone();
self.source_workspace.set_reachable(disk.reachable.clone());
self.show_source_file(false);
self.source_diagnostics = error.diagnostics().to_vec();
self.source_version += 1;
@@ -3690,11 +3838,13 @@ impl App {
let column = prefix
.rfind('\n')
.map_or(offset, |start| offset - start - 1);
self.source_jump = Some(text_editor::Cursor {
position: text_editor::Position { line, column },
selection: None,
});
self.source_select_line = true;
self.queue_source_reveal(
text_editor::Cursor {
position: text_editor::Position { line, column },
selection: None,
},
true,
);
}
fn create_source_file(&mut self) -> Result<(), String> {
@@ -4304,6 +4454,10 @@ fn read_snapshot(path: PathBuf) -> Result<LoadedSnapshot, String> {
#[path = "app/save_as_tests.rs"]
mod save_as_tests;
#[cfg(test)]
#[path = "app/repair_save_state_tests.rs"]
mod repair_save_state_tests;
#[cfg(test)]
mod source_project_tests {
use super::*;
+16
View File
@@ -213,6 +213,14 @@ impl App {
self.pending = None;
return Task::none();
}
if self.path.is_some()
|| self.hosted.session.as_ref().is_none_or(|session| {
session.resource_id != remote.resource_id
|| session.connection.base() != request.connection.base()
})
{
self.source_workspace.reset_navigation_session();
}
self.hosted.session = Some(Session {
connection: request.connection.clone(),
resource_id: remote.resource_id,
@@ -345,6 +353,14 @@ impl App {
match self.document.apply_compiled((*remote.compiled).clone()) {
Ok(_) => {
self.document.mark_saved(remote.compiled.clone());
if self.path.is_some()
|| self.hosted.session.as_ref().is_none_or(|session| {
session.resource_id != remote.resource_id
|| session.connection.base() != connection.base()
})
{
self.source_workspace.reset_navigation_session();
}
self.hosted.session = Some(Session {
connection,
resource_id: remote.resource_id,
@@ -0,0 +1,263 @@
use super::*;
const VALID: &str = concat!(
"arcadia 7;\r\n",
"project repair \"Repair 救援\" id \"9e8f0000-0000-4000-8000-000000000001\" {\r\n",
" oa_activity assess \"Assess\" id \"9e8f0000-0000-4000-8000-000000000002\" {}\r\n",
"}\r\n",
);
fn open(app: &mut App, path: &std::path::Path) {
let _ = app.update(Message::Loaded(Ok(Some(
read_snapshot(path.to_owned()).unwrap(),
))));
}
fn edit(app: &mut App, text: &str) {
let _ = app.update(Message::SourceEdit(text_editor::Action::SelectAll));
let _ = app.update(Message::SourceEdit(text_editor::Action::Edit(
text_editor::Edit::Paste(Arc::new(text.into())),
)));
}
fn save(app: &mut App, path: &std::path::Path) {
let receipt = write_snapshot(
app.canvas_document,
app.document.revision(),
app.document.snapshot(),
path.to_owned(),
app.disk_project.clone(),
)
.unwrap();
let _ = app.update(Message::Saved(Ok(Some(receipt))));
}
#[test]
fn repair_to_previous_saved_bytes_requires_save_at_new_destination_and_guards_close() {
for extra in [
" include \"missing.arcadia\";\r\n",
" oa_activity assess \"Duplicate\" id \"9e8f0000-0000-4000-8000-000000000003\" {}\r\n",
] {
let first = tempfile::tempdir().unwrap();
let second = tempfile::tempdir().unwrap();
let first_path = first.path().canonicalize().unwrap().join("project.arcadia");
let second_path = second
.path()
.canonicalize()
.unwrap()
.join("project.arcadia");
let invalid = VALID.strip_suffix("}\r\n").unwrap().to_owned() + extra + "}\r\n";
std::fs::write(&first_path, VALID).unwrap();
std::fs::write(&second_path, &invalid).unwrap();
let mut app = App::with_project(Project::empty());
open(&mut app, &first_path);
assert!(!app.dirty());
let before = app.document.snapshot();
let revision = app.document.revision();
open(&mut app, &second_path);
assert!(!app.source_workspace.applied);
assert!(Arc::ptr_eq(&before, &app.document.snapshot()));
edit(&mut app, VALID);
assert!(app.apply_source(), "{}", app.status);
assert!(app.source_workspace.applied);
assert!(!app.source_dirty());
assert_eq!(app.document.bundle(), &before.bundle);
assert_eq!(app.project(), &before.decoded.project);
assert_eq!(app.document.revision(), revision);
assert!(
!app.document.can_undo(),
"Equal content creates no history step"
);
assert!(app.document.dirty());
assert_eq!(app.hosted_label(), "Unsaved changes");
assert_eq!(std::fs::read(&second_path).unwrap(), invalid.as_bytes());
assert_eq!(std::fs::read(&first_path).unwrap(), VALID.as_bytes());
let close = window::Id::unique();
let task = app.update(Message::Request(Pending::Close(close)));
assert!(iced_runtime::task::into_stream(task).is_none());
assert!(matches!(app.pending, Some(Pending::Close(id)) if id == close));
let _ = app.update(Message::Cancel);
save(&mut app, &second_path);
assert!(!app.dirty());
assert_eq!(app.hosted_label(), "All changes saved");
assert_eq!(std::fs::read(&second_path).unwrap(), VALID.as_bytes());
assert_eq!(std::fs::read(&first_path).unwrap(), VALID.as_bytes());
}
}
#[test]
fn repair_history_compares_to_new_disk_baseline_and_then_successful_save() {
let directory = tempfile::tempdir().unwrap();
let path = directory
.path()
.canonicalize()
.unwrap()
.join("project.arcadia");
std::fs::write(&path, VALID).unwrap();
let mut app = App::with_project(Project::empty());
open(&mut app, &path);
let before = app.document.snapshot();
let invalid = format!("{VALID} unfinished {{");
std::fs::write(&path, &invalid).unwrap();
open(&mut app, &path);
let repaired = format!("{VALID}// Repaired rationale\r\n");
edit(&mut app, &repaired);
assert!(app.apply_source());
assert!(app.dirty());
let _ = app.update(Message::Undo);
assert_eq!(app.document.bundle(), &before.bundle);
assert!(
app.dirty(),
"Old saved bytes are not saved at the repair destination"
);
let _ = app.update(Message::Redo);
assert!(app.dirty());
assert_eq!(std::fs::read(&path).unwrap(), invalid.as_bytes());
std::fs::write(&path, "external edit").unwrap();
let failed = write_snapshot(
app.canvas_document,
app.document.revision(),
app.document.snapshot(),
path.clone(),
app.disk_project.clone(),
)
.unwrap_err();
let _ = app.update(Message::Saved(Err(failed)));
assert!(app.dirty());
assert_eq!(std::fs::read(&path).unwrap(), b"external edit");
std::fs::write(&path, &invalid).unwrap();
save(&mut app, &path);
assert!(!app.dirty());
let _ = app.update(Message::Undo);
assert!(app.dirty());
assert_eq!(app.document.bundle(), &before.bundle);
let _ = app.update(Message::Redo);
assert!(!app.dirty(), "Redo to the new saved snapshot is clean");
assert_eq!(std::fs::read(&path).unwrap(), repaired.as_bytes());
}
#[test]
fn valid_equal_content_at_distinct_destinations_stays_clean() {
let first = tempfile::tempdir().unwrap();
let second = tempfile::tempdir().unwrap();
let first_path = first.path().canonicalize().unwrap().join("project.arcadia");
let second_path = second
.path()
.canonicalize()
.unwrap()
.join("project.arcadia");
std::fs::write(&first_path, VALID).unwrap();
std::fs::write(&second_path, VALID).unwrap();
let mut app = App::with_project(Project::empty());
open(&mut app, &first_path);
let before = app.document.bundle().clone();
open(&mut app, &second_path);
assert_eq!(app.document.bundle(), &before);
assert_eq!(app.path.as_ref(), Some(&second_path));
assert!(!app.dirty());
assert_eq!(app.hosted_label(), "All changes saved");
}
#[test]
fn recovering_applied_repair_rebinds_rolled_back_disk_bytes_without_changing_model() {
let first = tempfile::tempdir().unwrap();
let second = tempfile::tempdir().unwrap();
let first_path = first.path().canonicalize().unwrap().join("project.arcadia");
let root = second.path().canonicalize().unwrap();
let path = root.join("project.arcadia");
let before = VALID.replace("Repair 救援", "Before 救援");
std::fs::write(&first_path, VALID).unwrap();
std::fs::write(&path, VALID).unwrap();
let journal = root.join(".arcadia-save-project.arcadia.journal");
std::fs::create_dir(&journal).unwrap();
std::fs::write(
journal.join("journal.json"),
br#"{"version":1,"entry":"project.arcadia","files":[{"path":"project.arcadia","before":true,"write":true}]}"#,
)
.unwrap();
std::fs::write(journal.join("0.before"), &before).unwrap();
std::fs::write(journal.join("0.after"), VALID).unwrap();
let mut app = App::with_project(Project::empty());
open(&mut app, &first_path);
let accepted = app.document.snapshot();
open(&mut app, &path);
assert_eq!(app.pending_recovery.as_ref(), Some(&path));
assert!(!app.source_workspace.applied);
assert!(app.apply_source());
assert!(
!app.dirty(),
"Current bytes still match disk before rollback"
);
let _ = app.update(Message::SourceRecovered(recover_snapshot(path.clone())));
assert!(app.pending_recovery.is_none());
assert!(!journal.exists());
assert_eq!(std::fs::read(&path).unwrap(), before.as_bytes());
assert!(Arc::ptr_eq(&accepted, &app.document.snapshot()));
assert!(!app.source_dirty());
assert!(app.dirty(), "Recovery changed disk, not the accepted model");
assert_eq!(app.hosted_label(), "Unsaved changes");
save(&mut app, &path);
assert!(!app.dirty());
assert_eq!(std::fs::read(&path).unwrap(), VALID.as_bytes());
}
#[test]
fn recovery_missing_entry_or_failed_reload_preserves_current_destination_save_authority() {
for (current_destination, failed_reload) in
[(true, false), (false, false), (true, true), (false, true)]
{
let directory = tempfile::tempdir().unwrap();
let root = directory.path().canonicalize().unwrap();
let path = root.join("project.arcadia");
std::fs::write(&path, VALID).unwrap();
let mut app = App::with_project(Project::empty());
open(&mut app, &path);
let accepted = app.document.snapshot();
let journal = root.join(".arcadia-save-project.arcadia.journal");
std::fs::create_dir(&journal).unwrap();
std::fs::write(
journal.join("journal.json"),
br#"{"version":1,"entry":"project.arcadia","files":[{"path":"project.arcadia","before":false,"write":true}]}"#,
)
.unwrap();
std::fs::write(journal.join("0.after"), VALID).unwrap();
open(&mut app, &path);
assert!(app.apply_source());
assert!(!app.dirty());
let destination = tempfile::tempdir().unwrap();
let saved_elsewhere = destination
.path()
.canonicalize()
.unwrap()
.join("project.arcadia");
if !current_destination {
save(&mut app, &saved_elsewhere);
assert_eq!(app.path.as_ref(), Some(&saved_elsewhere));
assert_eq!(app.pending_recovery.as_ref(), Some(&path));
}
let mut receipt = recover_snapshot(path.clone()).unwrap();
assert!(
receipt.disk.as_ref().unwrap().bundle.files.is_empty(),
"Missing entry reloads as an empty repair workspace"
);
if failed_reload {
// Separately exercise the adapter's successful-recovery/failed-read
// boundary; first-save rollback itself does not cause a read error.
receipt.disk = Err("Injected post-recovery reload failure".into());
}
let _ = app.update(Message::SourceRecovered(Ok(receipt)));
assert!(!path.exists());
assert!(!journal.exists());
assert!(app.pending_recovery.is_none());
assert!(Arc::ptr_eq(&accepted, &app.document.snapshot()));
assert_eq!(app.dirty(), current_destination);
if current_destination {
let _ = app.update(Message::Request(Pending::New));
assert!(matches!(app.pending, Some(Pending::New)));
} else {
assert_eq!(app.path.as_ref(), Some(&saved_elsewhere));
assert_eq!(std::fs::read(&saved_elsewhere).unwrap(), VALID.as_bytes());
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,219 @@
//! Keep Iced's single-line input from silently filtering pasted control bytes.
//! Only the alias field uses this adapter. The child retains editing and focus.
use iced::advanced::{
Clipboard, Layout, Shell, Widget, clipboard, layout, overlay, renderer, text, widget,
};
use iced::{Element, Event, Length, Rectangle, Size, Vector, keyboard, mouse};
pub(super) fn guard<'a, Message: Clone + 'a, Theme: 'a, R: text::Renderer + 'a>(
input: Element<'a, Message, Theme, R>,
rejected: Option<Message>,
) -> Element<'a, Message, Theme, R> {
Element::new(AliasInput { input, rejected })
}
struct AliasInput<'a, Message, Theme, R> {
input: Element<'a, Message, Theme, R>,
rejected: Option<Message>,
}
#[derive(Default)]
struct State {
modifiers: keyboard::Modifiers,
}
// Each fresh child clipboard read uses the checked snapshot. Iced may reuse its
// previously admitted paste while V is held, until KeyReleased clears that cache.
struct CapturedClipboard<'a> {
content: Option<String>,
original: &'a mut dyn Clipboard,
}
impl Clipboard for CapturedClipboard<'_> {
fn read(&self, kind: clipboard::Kind) -> Option<String> {
if kind == clipboard::Kind::Standard {
self.content.clone()
} else {
self.original.read(kind)
}
}
fn write(&mut self, kind: clipboard::Kind, contents: String) {
self.original.write(kind, contents);
}
}
impl<Message: Clone, Theme, R: text::Renderer> Widget<Message, Theme, R>
for AliasInput<'_, Message, Theme, R>
{
fn size(&self) -> Size<Length> {
self.input.as_widget().size()
}
fn size_hint(&self) -> Size<Length> {
self.input.as_widget().size_hint()
}
fn tag(&self) -> widget::tree::Tag {
widget::tree::Tag::of::<State>()
}
fn state(&self) -> widget::tree::State {
widget::tree::State::new(State::default())
}
fn children(&self) -> Vec<widget::Tree> {
vec![widget::Tree::new(self.input.as_widget())]
}
fn diff(&self, tree: &mut widget::Tree) {
tree.diff_children(std::slice::from_ref(&self.input));
}
fn layout(
&mut self,
tree: &mut widget::Tree,
renderer: &R,
limits: &layout::Limits,
) -> layout::Node {
self.input
.as_widget_mut()
.layout(&mut tree.children[0], renderer, limits)
}
fn draw(
&self,
tree: &widget::Tree,
renderer: &mut R,
theme: &Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
) {
self.input.as_widget().draw(
&tree.children[0],
renderer,
theme,
style,
layout,
cursor,
viewport,
);
}
fn operate(
&mut self,
tree: &mut widget::Tree,
layout: Layout<'_>,
renderer: &R,
operation: &mut dyn widget::Operation,
) {
self.input
.as_widget_mut()
.operate(&mut tree.children[0], layout, renderer, operation);
}
fn update(
&mut self,
tree: &mut widget::Tree,
event: &Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &R,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) {
let focused = tree.children[0]
.state
.downcast_ref::<iced::widget::text_input::State<R::Paragraph>>()
.is_focused();
let state = tree.state.downcast_mut::<State>();
// Iced 0.14.2 uses stored ModifiersChanged state, not KeyPressed.modifiers.
// Mirror its Escape reset and its Latin/physical-key paste shortcut.
if let Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) = event {
state.modifiers = *modifiers;
}
let paste = matches!(event,
Event::Keyboard(keyboard::Event::KeyPressed { key, physical_key, .. })
if key.to_latin(*physical_key) == Some('v')
&& state.modifiers.command() && !state.modifiers.alt());
if focused
&& paste
&& let Some(rejected) = &self.rejected
{
let content = clipboard.read(clipboard::Kind::Standard);
if content
.as_ref()
.is_some_and(|value| value.chars().any(char::is_control))
{
// Do not invoke the child: even an empty replacement would erase
// its selection. Approval invalidation is an explicit App event.
shell.publish(rejected.clone());
shell.capture_event();
return;
}
self.input.as_widget_mut().update(
&mut tree.children[0],
event,
layout,
cursor,
renderer,
&mut CapturedClipboard {
content,
original: clipboard,
},
shell,
viewport,
);
return;
}
self.input.as_widget_mut().update(
&mut tree.children[0],
event,
layout,
cursor,
renderer,
clipboard,
shell,
viewport,
);
// In Iced 0.14.2 the only KeyPressed branch that removes focus is its
// Escape branch, which also resets stored modifiers. Observe that branch
// after its text/shortcut early returns and effective-key conversion.
if focused
&& matches!(event, Event::Keyboard(keyboard::Event::KeyPressed { .. }))
&& !tree.children[0]
.state
.downcast_ref::<iced::widget::text_input::State<R::Paragraph>>()
.is_focused()
{
tree.state.downcast_mut::<State>().modifiers = keyboard::Modifiers::default();
}
}
fn mouse_interaction(
&self,
tree: &widget::Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &R,
) -> mouse::Interaction {
self.input.as_widget().mouse_interaction(
&tree.children[0],
layout,
cursor,
viewport,
renderer,
)
}
fn overlay<'a>(
&'a mut self,
tree: &'a mut widget::Tree,
layout: Layout<'a>,
renderer: &R,
viewport: &Rectangle,
translation: Vector,
) -> Option<overlay::Element<'a, Message, Theme, R>> {
self.input.as_widget_mut().overlay(
&mut tree.children[0],
layout,
renderer,
viewport,
translation,
)
}
}
#[cfg(all(test, debug_assertions))]
mod tests;
@@ -0,0 +1,220 @@
use super::*;
use crate::views::source_tests::FontLayout;
use iced::keyboard::{
Key, Modifiers,
key::{Code, Named, Physical},
};
use std::cell::Cell;
#[derive(Debug, Clone, PartialEq)]
enum Signal {
Input(String),
Rejected,
}
struct ClipboardText {
text: String,
reads: Cell<usize>,
}
impl Clipboard for ClipboardText {
fn read(&self, _: clipboard::Kind) -> Option<String> {
self.reads.set(self.reads.get() + 1);
Some(self.text.clone())
}
fn write(&mut self, _: clipboard::Kind, _: String) {}
}
type InputState = iced::widget::text_input::State<<FontLayout as text::Renderer>::Paragraph>;
struct Mounted {
input: Element<'static, Signal, iced::Theme, FontLayout>,
tree: widget::Tree,
node: layout::Node,
clipboard: ClipboardText,
messages: Vec<Signal>,
}
impl Mounted {
fn new(focused: bool, enabled: bool, modifiers: Modifiers) -> Self {
let mut child = iced::widget::text_input("Alias", "send_water");
if enabled {
child = child.on_input(Signal::Input);
}
let mut input = guard(child.into(), enabled.then_some(Signal::Rejected));
let mut tree = widget::Tree::new(input.as_widget());
let node = input.as_widget_mut().layout(
&mut tree,
&FontLayout,
&layout::Limits::new(Size::ZERO, Size::new(500., 40.)),
);
if focused {
let state = tree.children[0].state.downcast_mut::<InputState>();
state.focus();
state.select_range(0, 10);
}
let mut mounted = Self {
input,
tree,
node,
clipboard: ClipboardText {
text: "foo\nbar".into(),
reads: Cell::new(0),
},
messages: vec![],
};
mounted.event(Event::Keyboard(keyboard::Event::ModifiersChanged(
modifiers,
)));
mounted
}
fn state(&self) -> &InputState {
self.tree.children[0].state.downcast_ref::<InputState>()
}
fn event(&mut self, event: Event) -> bool {
let mut shell = Shell::new(&mut self.messages);
self.input.as_widget_mut().update(
&mut self.tree,
&event,
Layout::new(&self.node),
mouse::Cursor::Unavailable,
&FontLayout,
&mut self.clipboard,
&mut shell,
&Rectangle::new(iced::Point::ORIGIN, Size::new(500., 40.)),
);
shell.is_event_captured()
}
}
fn key(key: Key, modified_key: Key, code: Code) -> Event {
Event::Keyboard(keyboard::Event::KeyPressed {
key,
modified_key,
physical_key: Physical::Code(code),
location: keyboard::Location::Standard,
modifiers: Modifiers::empty(),
text: None,
repeat: false,
})
}
fn paste() -> Event {
key(
Key::Character("v".into()),
Key::Character("v".into()),
Code::KeyV,
)
}
#[test]
fn paste_refusal_matches_child_focus_enabled_and_stored_modifier_protocol() {
for focused in [false, true] {
for enabled in [false, true] {
for modifiers in [
Modifiers::empty(),
Modifiers::SHIFT,
Modifiers::COMMAND,
Modifiers::COMMAND | Modifiers::ALT,
Modifiers::COMMAND | Modifiers::SHIFT,
] {
let mut mounted = Mounted::new(focused, enabled, modifiers);
let before = mounted.state().cursor();
let expected = focused && enabled && modifiers.command() && !modifiers.alt();
let captured = mounted.event(paste());
assert_eq!(
mounted.messages,
if expected {
vec![Signal::Rejected]
} else {
vec![]
}
);
assert_eq!(mounted.clipboard.reads.get(), usize::from(expected));
assert_eq!(mounted.state().cursor(), before);
if expected {
assert!(captured);
}
}
}
}
}
#[test]
fn effective_escape_reset_follows_child_after_early_returns() {
// Raw Escape mapped to Home must not clear only the guard's Command state.
let mut mounted = Mounted::new(true, true, Modifiers::COMMAND);
mounted.event(key(
Key::Named(Named::Escape),
Key::Named(Named::Home),
Code::Escape,
));
assert!(mounted.state().is_focused());
assert!(mounted.event(paste()));
assert_eq!(mounted.messages, vec![Signal::Rejected]);
// Effective Escape clears both states; a later focus operation does not
// invent a new ModifiersChanged event or revive the previous Command state.
let mut mounted = Mounted::new(true, true, Modifiers::COMMAND);
mounted.event(key(
Key::Named(Named::Home),
Key::Named(Named::Escape),
Code::Home,
));
assert!(!mounted.state().is_focused());
mounted.tree.children[0]
.state
.downcast_mut::<InputState>()
.focus();
mounted.event(paste());
assert!(mounted.messages.is_empty());
assert_eq!(mounted.clipboard.reads.get(), 0);
// Printable text returns before effective Escape and leaves modifiers live.
let mut mounted = Mounted::new(true, true, Modifiers::COMMAND);
let mut event = key(
Key::Named(Named::Home),
Key::Named(Named::Escape),
Code::Home,
);
if let Event::Keyboard(keyboard::Event::KeyPressed { text, .. }) = &mut event {
*text = Some("x".into());
}
mounted.event(event);
assert!(mounted.state().is_focused());
assert_eq!(mounted.messages, vec![Signal::Input("x".into())]);
mounted.messages.clear();
mounted.event(paste());
assert_eq!(mounted.messages, vec![Signal::Rejected]);
}
#[test]
fn held_paste_cache_contains_only_previously_admitted_text() {
let mut mounted = Mounted::new(true, true, Modifiers::COMMAND);
mounted.clipboard.text = "water".into();
mounted.event(paste());
assert_eq!(mounted.messages, vec![Signal::Input("water".into())]);
mounted.messages.clear();
mounted.clipboard.text = "other".into();
mounted.event(paste());
assert_eq!(
mounted.messages,
vec![Signal::Input("waterwater".into())],
"Iced reuses its first admitted paste while the key is held"
);
mounted.messages.clear();
let before = mounted.state().cursor();
mounted.clipboard.text = "bad\tvalue".into();
mounted.event(paste());
assert_eq!(mounted.messages, vec![Signal::Rejected]);
assert_eq!(mounted.state().cursor(), before);
mounted.messages.clear();
mounted.event(Event::Keyboard(keyboard::Event::KeyReleased {
key: Key::Character("v".into()),
modified_key: Key::Character("v".into()),
physical_key: Physical::Code(Code::KeyV),
location: keyboard::Location::Standard,
modifiers: Modifiers::empty(),
}));
mounted.clipboard.text = "later".into();
mounted.event(paste());
assert_eq!(
mounted.messages,
vec![Signal::Input("waterwaterlater".into())]
);
}
@@ -0,0 +1,303 @@
//! Display-only reuse after a guarded alias rename. This is not model authority.
use iced::{advanced::text::Renderer, widget::text_editor};
use std::sync::Arc;
/// Replace exact, unchanged-line-count source in an existing editor.
///
/// The caller must first authorize/commit the model change and must reconstruct
/// from accepted source on false. Preflight failures do not mutate the editor;
/// a failed final readback can leave it changed. On changing success the cursor
/// is at 0:0 without selection; the caller restores its approved origin/reveal.
/// Direct Content actions deliberately bypass App draft edits and Undo history.
pub(super) fn replace<R: Renderer>(
editor: &mut text_editor::Content<R>,
before: &str,
after: &str,
) -> bool {
if editor.text() != before {
return false;
}
let Some(old_lines) = lines(before) else {
return false;
};
let Some(new_lines) = lines(after) else {
return false;
};
if old_lines.len() != new_lines.len() || old_lines.len() != editor.line_count() {
return false;
}
let mut patches = Vec::new();
for (line, ((old, old_ending), (new, new_ending))) in
old_lines.into_iter().zip(new_lines).enumerate()
{
let Some(actual) = editor.line(line) else {
return false;
};
// Cosmic also recognizes bare CR and LFCR. Comparing the actual lines
// catches its greedy LFCR interpretation of e.g. "x\n\r\ny" too.
if old_ending != new_ending || actual.text != old || actual.ending != old_ending {
return false;
}
if old == new {
continue;
}
let mut start = old
.bytes()
.zip(new.bytes())
.take_while(|(a, b)| a == b)
.count();
while !old.is_char_boundary(start) || !new.is_char_boundary(start) {
start -= 1;
}
let mut suffix = old[start..]
.bytes()
.rev()
.zip(new[start..].bytes().rev())
.take_while(|(a, b)| a == b)
.count();
while !old.is_char_boundary(old.len() - suffix) || !new.is_char_boundary(new.len() - suffix)
{
suffix -= 1;
}
// All positions and owned payloads are prepared before the first edit.
patches.push((
line,
start,
old.len() - suffix,
Arc::new(new[start..new.len() - suffix].to_owned()),
));
}
if patches.is_empty() {
return true;
}
let empty = Arc::new(String::new());
for (line, start, end, replacement) in patches.into_iter().rev() {
select(editor, line, start, end);
editor.perform(text_editor::Action::Edit(text_editor::Edit::Paste(
replacement,
)));
}
// Iced overwrites its earliest-change marker on each Edit. An explicit
// zero-width selection + empty Paste changes no bytes, but marks line zero.
// This also refreshes previously unhighlighted lines before the first patch.
// It resets only line zero's text cache; other unchanged lines retain theirs.
select(editor, 0, 0, 0);
editor.perform(text_editor::Action::Edit(text_editor::Edit::Paste(empty)));
editor.text() == after
}
fn select<R: Renderer>(
editor: &mut text_editor::Content<R>,
line: usize,
start: usize,
end: usize,
) {
editor.move_to(text_editor::Cursor {
position: text_editor::Position {
line,
column: start,
},
// move_to(None) does not clear a previous selection in this Iced version.
selection: Some(text_editor::Position { line, column: end }),
});
}
fn lines(source: &str) -> Option<Vec<(&str, text_editor::LineEnding)>> {
use text_editor::LineEnding;
let mut result = Vec::new();
let mut parts = source.split('\n').peekable();
while let Some(part) = parts.next() {
let (text, ending) = if parts.peek().is_none() {
(part, LineEnding::None)
} else if let Some(text) = part.strip_suffix('\r') {
(text, LineEnding::CrLf)
} else {
(part, LineEnding::Lf)
};
if text.contains('\r')
|| (text.is_empty()
&& ending == LineEnding::CrLf
&& result
.last()
.is_some_and(|(_, previous)| *previous == LineEnding::Lf))
{
return None;
}
result.push((text, ending));
}
Some(result)
}
#[cfg(all(test, debug_assertions))]
mod tests {
use super::*;
use crate::views::source_tests::FontLayout;
use iced::advanced::{layout, text::Highlighter, widget::Tree};
use iced::{Element, Font, Length, Size};
use std::{cell::RefCell, ops::Range};
#[test]
fn exact_text_matrix_and_reverse_preserve_endings() {
for (before, after) in [
("", ""),
("", "alias"),
("alias", ""),
("same", "same"),
("a\n", "alias\n"),
("a\r\n", "alias\r\n"),
("\r\na\r\n\r\n", "\r\nlong_alias\r\n\r\n"),
("\na\n\n", "\nlong_alias\n\n"),
("a\r\nb\nc", "long_a\r\nlong_b\nlong_c"),
(
"雨🙂 e\u{301} @a @a // a",
"雨🙂 e\u{301} @a_long @a_long // a",
),
("@abc", "@abcdef"),
("@abcdef", "@abc"),
("@abc_suffix", "@def_suffix"),
("@none", "@identifier"),
// Shared prefix/suffix bytes inside distinct UTF-8 codepoints must
// not be used as String split positions, even outside alias scope.
("雨xé", "雪xê"),
("é", "©"),
(
"unchanged\n@a\nunchanged\n@a\n",
"unchanged\n@long\nunchanged\n@long\n",
),
] {
let mut editor = text_editor::Content::<FontLayout>::with_text(before);
assert!(
replace(&mut editor, before, after),
"{before:?} -> {after:?}"
);
assert_eq!(editor.text(), after);
let expected = text_editor::Content::<FontLayout>::with_text(after);
assert_eq!(editor.line_count(), expected.line_count());
for (actual, expected) in editor.lines().zip(expected.lines()) {
assert_eq!(actual.text, expected.text);
assert_eq!(actual.ending, expected.ending);
}
if before != after {
assert_eq!(
editor.cursor().position,
text_editor::Position { line: 0, column: 0 }
);
assert_eq!(editor.cursor().selection, None);
}
assert!(replace(&mut editor, after, before));
assert_eq!(editor.text(), before);
}
}
#[test]
fn all_preflight_refusals_leave_text_cursor_and_selection_unchanged() {
for (actual, before, after) in [
("live", "stale", "changed"),
("a\nb", "a\nb", "long\nb\nc"),
("a\nb", "a\nb", "long\r\nb"),
// Refusal on a later line must not apply the earlier planned edit.
("a\nb\r\n", "a\nb\r\n", "long\nb\n"),
("a\rb", "a\rb", "long\rb"),
("a\n\rb", "a\n\rb", "long\n\rb"),
("a\n\r\nb", "a\n\r\nb", "long\n\r\nb"),
// The replacement must not introduce a greedy LFCR boundary either.
("a\nx\r\n", "a\nx\r\n", "a\n\r\n"),
("a", "a", "long\r"),
] {
let mut editor = text_editor::Content::<FontLayout>::with_text(actual);
select(&mut editor, 0, 0, 1);
let cursor = editor.cursor();
let selection = editor.selection();
assert!(
!replace(&mut editor, before, after),
"{before:?} -> {after:?}"
);
assert_eq!(editor.text(), actual);
assert_eq!(editor.cursor(), cursor);
assert_eq!(editor.selection(), selection);
}
}
#[test]
fn unchanged_content_preserves_selection_and_next_direct_edit_works() {
let mut editor = text_editor::Content::<FontLayout>::with_text("@a");
select(&mut editor, 0, 1, 2);
let cursor = editor.cursor();
assert!(replace(&mut editor, "@a", "@a"));
assert_eq!(editor.cursor(), cursor);
assert!(replace(&mut editor, "@a", "@long"));
editor.move_to(text_editor::Cursor {
position: text_editor::Position { line: 0, column: 5 },
selection: None,
});
editor.perform(text_editor::Action::Edit(text_editor::Edit::Insert('!')));
assert_eq!(editor.text(), "@long!");
}
thread_local! {
static CHANGES: RefCell<Vec<usize>> = const { RefCell::new(Vec::new()) };
}
struct Tracked(crate::highlight::ArcadiaHighlighter);
impl Highlighter for Tracked {
type Settings = Arc<str>;
type Highlight = oa_core::language::TokenClass;
type Iterator<'a> = std::vec::IntoIter<(Range<usize>, Self::Highlight)>;
fn new(settings: &Self::Settings) -> Self {
Self(crate::highlight::ArcadiaHighlighter::new(settings))
}
fn update(&mut self, settings: &Self::Settings) {
self.0.update(settings);
}
fn change_line(&mut self, line: usize) {
CHANGES.with(|changes| changes.borrow_mut().push(line));
self.0.change_line(line);
}
fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_> {
self.0.highlight_line(line)
}
fn current_line(&self) -> usize {
self.0.current_line()
}
}
fn view(
editor: &text_editor::Content<FontLayout>,
source: Arc<str>,
) -> Element<'_, (), iced::Theme, FontLayout> {
text_editor(editor)
.font(Font::MONOSPACE)
.size(14)
.height(Length::Fill)
.highlight_with::<Tracked>(source, crate::highlight::format)
.into()
}
#[test]
fn already_laid_out_editor_notifies_highlighter_from_zero_after_later_line_patch() {
let before = "// earlier\n// unmodified\n@a";
let after = "// earlier\n// unmodified\n@none";
let mut editor = text_editor::Content::<FontLayout>::with_text(before);
let limits = layout::Limits::new(Size::ZERO, Size::new(400., 60.));
let mut tree = {
let mut widget = view(&editor, Arc::from(before));
let mut tree = Tree::new(widget.as_widget());
let _ = widget
.as_widget_mut()
.layout(&mut tree, &FontLayout, &limits);
tree
};
CHANGES.with(|changes| changes.borrow_mut().clear());
assert!(replace(&mut editor, before, after));
{
let mut widget = view(&editor, Arc::from(after));
let _ = widget
.as_widget_mut()
.layout(&mut tree, &FontLayout, &limits);
}
// Font/metrics/bounds are already stable. This notification must come
// from the helper's empty edit, not a fresh renderer initialization.
CHANGES.with(|changes| assert_eq!(*changes.borrow(), [0]));
assert_eq!(editor.text(), after);
}
}
@@ -0,0 +1,449 @@
//! Real paragraph advances and clipping through the actual preview dialog.
//! Native screenshots additionally check raster ink and the platform renderer.
use super::*;
use crate::views::source_tests::FontLayout;
use iced::advanced::{Layout, layout, renderer, text as shaped, widget};
use iced::{Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, Vector};
use std::collections::{BTreeMap, BTreeSet};
struct Glyph {
text: String,
paragraph_y: u32,
line: usize,
bytes: std::ops::Range<usize>,
bounds: Rectangle,
clip: Rectangle,
}
struct GlyphRecorder {
wanted: BTreeSet<String>,
transforms: Vec<Transformation>,
clips: Vec<Rectangle>,
glyphs: Vec<Glyph>,
quads: Vec<Rectangle>,
}
impl GlyphRecorder {
fn new(wanted: BTreeSet<String>, viewport: Rectangle) -> Self {
Self {
wanted,
transforms: vec![Transformation::IDENTITY],
clips: vec![viewport],
glyphs: vec![],
quads: vec![],
}
}
fn transform(&self) -> Transformation {
*self.transforms.last().unwrap()
}
fn clip(&self, bounds: Rectangle) -> Rectangle {
self.clips
.last()
.unwrap()
.intersection(&(bounds * self.transform()))
.unwrap_or(Rectangle::with_size(Size::ZERO))
}
}
impl renderer::Renderer for GlyphRecorder {
fn start_layer(&mut self, bounds: Rectangle) {
self.clips.push(self.clip(bounds));
}
fn end_layer(&mut self) {
self.clips.pop().unwrap();
}
fn start_transformation(&mut self, transform: Transformation) {
self.transforms.push(self.transform() * transform);
}
fn end_transformation(&mut self) {
self.transforms.pop().unwrap();
}
fn reset(&mut self, bounds: Rectangle) {
self.transforms = vec![Transformation::IDENTITY];
self.clips = vec![bounds];
self.glyphs.clear();
self.quads.clear();
}
fn fill_quad(&mut self, quad: renderer::Quad, _: impl Into<Background>) {
self.quads.push(quad.bounds * self.transform());
}
fn allocate_image(
&mut self,
handle: &iced::advanced::image::Handle,
callback: impl FnOnce(Result<iced::advanced::image::Allocation, iced::advanced::image::Error>)
+ Send
+ 'static,
) {
renderer::Renderer::allocate_image(&mut FontLayout, handle, callback);
}
}
impl shaped::Renderer for GlyphRecorder {
type Font = Font;
type Paragraph = <FontLayout as shaped::Renderer>::Paragraph;
type Editor = <FontLayout as shaped::Renderer>::Editor;
const ICON_FONT: Font = <FontLayout as shaped::Renderer>::ICON_FONT;
const CHECKMARK_ICON: char = <FontLayout as shaped::Renderer>::CHECKMARK_ICON;
const ARROW_DOWN_ICON: char = <FontLayout as shaped::Renderer>::ARROW_DOWN_ICON;
const SCROLL_UP_ICON: char = <FontLayout as shaped::Renderer>::SCROLL_UP_ICON;
const SCROLL_DOWN_ICON: char = <FontLayout as shaped::Renderer>::SCROLL_DOWN_ICON;
const SCROLL_LEFT_ICON: char = <FontLayout as shaped::Renderer>::SCROLL_LEFT_ICON;
const SCROLL_RIGHT_ICON: char = <FontLayout as shaped::Renderer>::SCROLL_RIGHT_ICON;
const ICED_LOGO: char = <FontLayout as shaped::Renderer>::ICED_LOGO;
fn default_font(&self) -> Font {
shaped::Renderer::default_font(&FontLayout)
}
fn default_size(&self) -> Pixels {
shaped::Renderer::default_size(&FontLayout)
}
fn fill_paragraph(
&mut self,
paragraph: &Self::Paragraph,
position: Point,
_: Color,
clip: Rectangle,
) {
let buffer = paragraph.buffer();
let text = buffer
.lines
.iter()
.map(|line| line.text())
.collect::<Vec<_>>()
.join("\n");
if !self.wanted.contains(&text) {
return;
}
let clip = self.clip(clip);
for run in buffer.layout_runs() {
for glyph in run.glyphs {
if run.text[glyph.start..glyph.end]
.chars()
.all(char::is_whitespace)
{
continue;
}
let bounds = Rectangle {
x: position.x + glyph.x + glyph.x_offset * glyph.font_size,
y: position.y + run.line_top,
width: glyph.w,
height: run.line_height,
} * self.transform();
self.glyphs.push(Glyph {
text: text.clone(),
paragraph_y: position.y.to_bits(),
line: run.line_i,
bytes: glyph.start..glyph.end,
bounds,
clip,
});
}
}
}
fn fill_editor(
&mut self,
editor: &Self::Editor,
position: Point,
color: Color,
clip: Rectangle,
) {
shaped::Renderer::fill_editor(&mut FontLayout, editor, position, color, clip);
}
fn fill_text(&mut self, text: shaped::Text, position: Point, color: Color, clip: Rectangle) {
shaped::Renderer::fill_text(&mut FontLayout, text, position, color, clip);
}
}
#[derive(Default)]
struct ScrollGeometry {
id: Option<widget::Id>,
bounds: Option<Rectangle>,
content: Option<Rectangle>,
offset: Vector,
}
impl widget::Operation for ScrollGeometry {
fn traverse(&mut self, visit: &mut dyn FnMut(&mut dyn widget::Operation)) {
visit(self);
}
fn scrollable(
&mut self,
id: Option<&widget::Id>,
bounds: Rectangle,
content: Rectangle,
offset: Vector,
_: &mut dyn widget::operation::Scrollable,
) {
if id == self.id.as_ref() {
self.bounds = Some(bounds);
self.content = Some(content);
self.offset = offset;
}
}
}
fn normalized(text: &str) -> String {
text.replace("\r\n", "\n").replace('\r', "\n")
}
fn required_chars(text: &str) -> BTreeSet<(usize, usize)> {
text.split('\n')
.enumerate()
.flat_map(|(line, text)| {
text.char_indices()
.filter(|(_, ch)| !ch.is_whitespace())
.map(move |(byte, _)| (line, byte))
})
.collect()
}
fn declarations(long: bool) -> App {
let name = if long {
format!("Assess {} request", "界🚀".repeat(90))
} else {
"Assess 救援 request".into()
};
let source = SourceBundle { entry: "project.arcadia".into(), files: BTreeMap::from([
("project.arcadia".into(), "arcadia 7;\r\nproject navigation_trial \"Navigation — 救援\" id \"9e8f0000-0000-4000-8000-000000000001\" {\r\n include \"救援/assess.arcadia\";\r\n}\r\n".into()),
("救援/assess.arcadia".into(), format!("// Comment @assess must not be a lexical use.\r\noa_activity assess \"{name}\" id \"9e8f0000-0000-4000-8000-000000000002\" {{\r\n description \"Keep @assess as prose, not a use.\";\r\n}}\r\n")),
]) };
let mut app = fixture();
app.document = Document::from_bundle(source, LIMITS).unwrap();
app.source_workspace = Workspace::new(app.document.bundle(), true);
app.source_workspace.active = "救援/assess.arcadia".into();
app.selected = app.project().id;
app.refresh_draft();
app.show_source_file(false);
let start = app
.source_workspace
.text()
.find("oa_activity assess")
.unwrap()
+ "oa_activity ".len();
app.source_editor.move_to(cursor(
app.source_workspace.text(),
start,
start + "assess".len(),
));
begin(&mut app);
let replacement = if long {
"a".repeat(255)
} else {
"assess_damage".into()
};
input(&mut app, &replacement);
let _ = preview(&mut app);
app
}
fn assert_page_glyphs_visible(app: &App, host: Size) {
let form = app.source_rename.form.as_ref().unwrap();
let ready = form.approval.as_ref().unwrap();
let file = &ready.preview.files()[form.file];
let mut expected = BTreeMap::<String, usize>::new();
for line in file.hunks()[form.hunk]
.lines()
.iter()
.skip(form.line)
.take(LINES_PER_PAGE)
{
for source in [
line.before_text(&ready.prepared.before().bundle.files[file.path()])
.unwrap(),
line.after_text(&ready.prepared.after().bundle.files[file.path()])
.unwrap(),
] {
if let Some(fragment) = preview::text_segment(source, form.segment) {
let text = normalized(fragment);
if !required_chars(&text).is_empty() {
*expected.entry(text).or_default() += 1;
}
}
}
}
assert!(!expected.is_empty());
let viewport = Rectangle::new(Point::ORIGIN, host);
let mut renderer = GlyphRecorder::new(expected.keys().cloned().collect(), viewport);
let editor = text_editor::Content::<GlyphRecorder>::new();
let mut view = dialog_content(app, &editor);
let mut tree = widget::Tree::new(view.as_widget());
let node =
view.as_widget_mut()
.layout(&mut tree, &renderer, &layout::Limits::new(Size::ZERO, host));
let mut geometry = ScrollGeometry {
id: Some(preview_scroll_id(form, ready.id)),
..ScrollGeometry::default()
};
view.as_widget_mut()
.operate(&mut tree, Layout::new(&node), &renderer, &mut geometry);
let bounds = geometry.bounds.unwrap();
let content = geometry.content.unwrap();
assert!(bounds.height >= 40.);
let maximum = (content.height - bounds.height).max(0.);
let steps = (maximum / (bounds.height * 0.5)).ceil() as usize;
let mut visible = BTreeMap::<(String, u32), BTreeSet<(usize, usize)>>::new();
let mut reserved_bar_gap = true;
for step in 0..=steps {
let offset = (step as f32 * bounds.height * 0.5).min(maximum);
view.as_widget_mut().operate(
&mut tree,
Layout::new(&node),
&renderer,
&mut widget::operation::scrollable::scroll_to(
preview_scroll_id(form, ready.id),
widget::operation::scrollable::AbsoluteOffset {
x: None,
y: Some(offset),
},
),
);
view.as_widget_mut()
.operate(&mut tree, Layout::new(&node), &renderer, &mut geometry);
assert!(
(geometry.offset.y - offset).abs() <= 0.5,
"actual scroll operation reaches the requested source offset"
);
renderer::Renderer::reset(&mut renderer, viewport);
view.as_widget().draw(
&tree,
&mut renderer,
&iced::Theme::Light,
&renderer::Style::default(),
Layout::new(&node),
iced::mouse::Cursor::Unavailable,
&viewport,
);
// The vertical scrollbar's actual painted thumb fixes its excluded x
// region; the outer scroll clip alone cannot detect overpainting.
let scrollbar_left = renderer
.quads
.iter()
.filter(|quad| {
quad.width > 0.
&& quad.width <= 16.
&& quad.height > 0.
&& quad.x >= bounds.x + bounds.width - 18.
&& quad.x + quad.width <= bounds.x + bounds.width + 0.5
&& quad.y >= bounds.y - 0.5
&& quad.y + quad.height <= bounds.y + bounds.height + 0.5
})
.map(|quad| quad.x)
.min_by(f32::total_cmp);
if maximum > 0. {
let left = scrollbar_left.expect("overflowing actual preview must paint its scrollbar");
reserved_bar_gap &= content.x + content.width <= left - 7.5;
}
for glyph in &renderer.glyphs {
let right = glyph.bounds.x + glyph.bounds.width;
if let Some(left) = scrollbar_left {
assert!(
right <= left - 0.5,
"source glyph under scrollbar: text={:?} cluster={:?} glyph={:?} bar x={left}",
glyph.text,
glyph.bytes,
glyph.bounds
);
}
assert!(
glyph.bounds.x >= content.x - 0.5 && right <= content.x + content.width + 0.5,
"source glyph escaped reserved width: {:?} {:?}",
glyph.text,
glyph.bounds
);
assert!(
glyph.bounds.x >= glyph.clip.x - 0.5
&& right <= glyph.clip.x + glyph.clip.width + 0.5,
"source glyph horizontally clipped: {:?} {:?} {:?}",
glyph.text,
glyph.bounds,
glyph.clip
);
if glyph.bounds.y >= glyph.clip.y - 0.5
&& glyph.bounds.y + glyph.bounds.height <= glyph.clip.y + glyph.clip.height + 0.5
{
let logical_line = glyph.text.split('\n').nth(glyph.line).unwrap();
let chars = logical_line
.char_indices()
.filter(|(byte, ch)| glyph.bytes.contains(byte) && !ch.is_whitespace())
.map(|(byte, _)| (glyph.line, byte));
visible
.entry((glyph.text.clone(), glyph.paragraph_y))
.or_default()
.extend(chars);
}
}
}
assert!(
reserved_bar_gap,
"source content must reserve actual scrollbar width plus gap"
);
assert!(
bounds.width >= host.width - 30.,
"preview must use available dialog width: {bounds:?} / {host:?}"
);
for (text, count) in expected {
let required = required_chars(&text);
let instances: Vec<_> = visible
.iter()
.filter(|((value, _), _)| value == &text)
.collect();
assert_eq!(
instances.len(),
count,
"all before/after occurrences must be seen: {text:?}"
);
for (_, seen) in instances {
assert_eq!(
seen, &required,
"every non-whitespace source cluster must be fully visible at some vertical offset: {text:?}"
);
}
}
}
#[test]
fn actual_preview_source_glyphs_clear_scrollbar_and_all_long_fragments_are_reachable() {
for long in [false, true] {
let mut app = declarations(long);
let ready = app
.source_rename
.form
.as_ref()
.unwrap()
.approval
.as_ref()
.unwrap()
.clone();
let invocation = app.source_rename.form.as_ref().unwrap().invocation;
let before = evidence(&app);
for (width, height) in [(1100., 700.), (580., 700.)] {
app.window_size = Size::new(width, height);
let host = Size::new((width - 84.).min(708.), height - 120.);
let total = segment_total(app.source_rename.form.as_ref().unwrap());
if long {
assert!(
total >= 3,
"include unbroken ASCII and wide Unicode across segments"
);
}
for segment in 0..total {
assert_page_glyphs_visible(&app, host);
if segment + 1 < total {
event(&mut app, Event::Segment(invocation, ready.id, true));
}
}
for _ in 1..total {
event(&mut app, Event::Segment(invocation, ready.id, false));
}
}
assert_eq!(
evidence(&app),
before,
"preview geometry/paging cannot alter transaction inputs"
);
assert_eq!(
app.source_rename
.form
.as_ref()
.unwrap()
.approval
.as_ref()
.unwrap()
.id,
ready.id
);
}
}
@@ -0,0 +1,310 @@
//! Execute the controller's scroll operations on a retained, scrolled dialog.
use super::*;
use crate::views::source_tests::FontLayout;
use iced::advanced::{Layout, layout, widget};
use iced::futures::StreamExt;
use iced::{Rectangle, Size, Vector};
const HOST: Size = Size::new(720., 660.);
fn paged_fixture() -> App {
let mut source = bundle();
let name = "Long engineering name 雨 ".repeat(18);
source.files.get_mut("defs.arcadia").unwrap().replace_range(
..,
&format!(
"oa_activity pump \"{name}\" id \"00000000-0000-0000-0000-000000000002\" {{}}\r\n\
oa_activity backup \"Backup\" id \"00000000-0000-0000-0000-000000000004\" {{}}\r\n"
),
);
let mut uses = String::new();
for index in 0..16 {
if index == 12 {
uses.push_str(&"// unchanged gap\r\n".repeat(10));
}
uses.push_str(&format!(
"interaction use_{index} \"{name}\" id \"00000000-0000-0000-0001-{index:012}\" {{ source @pump; target @backup; }}\r\n"
));
}
source.files.insert("uses.arcadia".into(), uses);
let mut app = fixture();
app.window_size = HOST;
app.document = Document::from_bundle(source, LIMITS).unwrap();
app.source_workspace = Workspace::new(app.document.bundle(), true);
app.source_workspace.active = "uses.arcadia".into();
app.show_source_file(false);
let start = app.source_workspace.text().find("source @pump").unwrap() + "source @".len();
app.source_editor
.move_to(cursor(app.source_workspace.text(), start, start + 4));
begin(&mut app);
input(&mut app, "pump_long");
let _ = preview(&mut app);
app
}
fn scroll_id(app: &App) -> widget::Id {
let form = app.source_rename.form.as_ref().unwrap();
preview_scroll_id(form, form.approval.as_ref().unwrap().id)
}
struct Geometry {
id: widget::Id,
offset: Option<Vector>,
}
impl widget::Operation for Geometry {
fn traverse(&mut self, visit: &mut dyn FnMut(&mut dyn widget::Operation)) {
visit(self);
}
fn scrollable(
&mut self,
id: Option<&widget::Id>,
_: Rectangle,
_: Rectangle,
offset: Vector,
_: &mut dyn widget::operation::Scrollable,
) {
if id == Some(&self.id) {
self.offset = Some(offset);
}
}
}
struct Mounted {
editor: text_editor::Content<FontLayout>,
tree: widget::Tree,
}
impl Mounted {
fn new(app: &App) -> Self {
let editor = text_editor::Content::<FontLayout>::new();
let tree = widget::Tree::new(dialog_content(app, &editor).as_widget());
Self { editor, tree }
}
fn operate(&mut self, app: &App, operation: &mut dyn widget::Operation) {
let mut view = dialog_content(app, &self.editor);
// Preserve the actual scroll state across the new page's view diff.
self.tree.diff(view.as_widget());
let node = view.as_widget_mut().layout(
&mut self.tree,
&FontLayout,
&layout::Limits::new(Size::ZERO, HOST),
);
view.as_widget_mut()
.operate(&mut self.tree, Layout::new(&node), &FontLayout, operation);
}
fn offset(&mut self, app: &App) -> f32 {
let mut geometry = Geometry {
id: scroll_id(app),
offset: None,
};
self.operate(app, &mut geometry);
geometry.offset.expect("mounted preview scrollable").y
}
fn scroll_down(&mut self, app: &App) -> f32 {
self.operate(
app,
&mut widget::operation::scrollable::scroll_to(
scroll_id(app),
widget::operation::scrollable::AbsoluteOffset {
x: None,
y: Some(10_000.),
},
),
);
let offset = self.offset(app);
assert!(offset > 10., "fixture must really be scrolled");
offset
}
async fn execute(&mut self, app: &App, task: Task<Message>) -> usize {
let mut count = 0;
if let Some(mut actions) = iced_runtime::task::into_stream(task) {
while let Some(action) = actions.next().await {
let iced_runtime::Action::Widget(mut operation) = action else {
panic!("preview paging must only schedule a widget operation");
};
self.operate(app, operation.as_mut());
count += 1;
}
}
count
}
}
#[tokio::test]
async fn explicit_navigation_resets_retained_scroll_but_id_change_alone_does_not() {
let mut app = paged_fixture();
let before = evidence(&app);
let form = app.source_rename.form.as_ref().unwrap();
let invocation = form.invocation;
let approval = form.approval.as_ref().unwrap().id;
let mut mounted = Mounted::new(&app);
mounted.scroll_down(&app);
let old_id = scroll_id(&app);
let task = app.update(Message::SourceRename(Event::File(
invocation, approval, true,
)));
assert_ne!(old_id, scroll_id(&app));
// Negative control: even after diff/layout with the new id and new file,
// Iced retains the previous offset until the returned operation executes.
assert!(mounted.offset(&app) > 10.);
assert_eq!(mounted.execute(&app, task).await, 1);
assert_eq!(mounted.offset(&app), 0.);
for navigation in [
Event::Line(invocation, approval, true),
Event::Segment(invocation, approval, true),
Event::Hunk(invocation, approval, true),
Event::File(invocation, approval, false),
Event::Search(invocation, "uses".into()),
Event::Search(invocation, "no-path-match".into()),
Event::Search(invocation, String::new()),
] {
mounted.scroll_down(&app);
let task = app.update(Message::SourceRename(navigation));
assert_eq!(mounted.execute(&app, task).await, 1);
assert_eq!(mounted.offset(&app), 0.);
assert_eq!(evidence(&app), before);
}
// Passive redraw and unchanged filter input preserve deliberate scrolling.
let offset = mounted.scroll_down(&app);
assert_eq!(mounted.offset(&app), offset);
let task = app.update(Message::SourceRename(Event::Search(
invocation,
String::new(),
)));
assert_eq!(mounted.execute(&app, task).await, 0);
assert_eq!(mounted.offset(&app), offset);
let task = app.update(Message::SourceRename(Event::Input(
invocation,
"pump_long".into(),
)));
assert_eq!(mounted.execute(&app, task).await, 0);
assert_eq!(mounted.offset(&app), offset);
let task = app.update(Message::SourceRename(Event::File(
invocation, approval, false,
)));
assert_eq!(
mounted.execute(&app, task).await,
0,
"clamped first-page request is a no-op"
);
assert_eq!(mounted.offset(&app), offset);
assert_eq!(evidence(&app), before);
}
#[tokio::test]
async fn delayed_page_and_approval_operations_cannot_reset_a_new_destination() {
let mut app = paged_fixture();
let before = evidence(&app);
let form = app.source_rename.form.as_ref().unwrap();
let invocation = form.invocation;
let old_approval = form.approval.as_ref().unwrap().id;
let mut mounted = Mounted::new(&app);
let old_page_task = app.update(Message::SourceRename(Event::File(
invocation,
old_approval,
true,
)));
let next_page_task = app.update(Message::SourceRename(Event::Line(
invocation,
old_approval,
true,
)));
assert_eq!(mounted.execute(&app, next_page_task).await, 1);
let offset = mounted.scroll_down(&app);
assert_eq!(mounted.execute(&app, old_page_task).await, 1);
assert_eq!(mounted.offset(&app), offset, "old page target is absent");
let old_approval_task = app.update(Message::SourceRename(Event::Search(
invocation,
"defs".into(),
)));
input(&mut app, "pump_new");
let _ = preview(&mut app); // Real new approval in the same invocation/page.
assert_ne!(
app.source_rename
.form
.as_ref()
.unwrap()
.approval
.as_ref()
.unwrap()
.id,
old_approval
);
let offset = mounted.scroll_down(&app);
assert_eq!(mounted.execute(&app, old_approval_task).await, 1);
assert_eq!(
mounted.offset(&app),
offset,
"old approval target is absent"
);
let task = app.update(Message::SourceRename(Event::File(
invocation,
old_approval,
true,
)));
assert_eq!(
mounted.execute(&app, task).await,
0,
"stale envelope is rejected before scheduling"
);
assert_eq!(mounted.offset(&app), offset);
assert_eq!(evidence(&app), before);
}
#[tokio::test]
async fn repeated_page_visits_filters_and_fast_preview_completion_have_distinct_destinations() {
let mut app = paged_fixture();
let before = evidence(&app);
let form = app.source_rename.form.as_ref().unwrap();
let invocation = form.invocation;
let approval = form.approval.as_ref().unwrap().id;
let mut mounted = Mounted::new(&app);
let first_visit = app.update(Message::SourceRename(Event::File(
invocation, approval, true,
)));
let next_page = app.update(Message::SourceRename(Event::Line(
invocation, approval, true,
)));
assert_eq!(mounted.execute(&app, next_page).await, 1);
let return_visit = app.update(Message::SourceRename(Event::Line(
invocation, approval, false,
)));
assert_eq!(mounted.execute(&app, return_visit).await, 1);
let offset = mounted.scroll_down(&app);
assert_eq!(mounted.execute(&app, first_visit).await, 1);
assert_eq!(
mounted.offset(&app),
offset,
"old visit to the identical page is stale"
);
let old_filter = app.update(Message::SourceRename(Event::Search(
invocation,
"uses".into(),
)));
let new_filter = app.update(Message::SourceRename(Event::Search(
invocation,
"us".into(),
)));
assert_eq!(mounted.execute(&app, new_filter).await, 1);
let offset = mounted.scroll_down(&app);
assert_eq!(mounted.execute(&app, old_filter).await, 1);
assert_eq!(
mounted.offset(&app),
offset,
"old filter on the same page is stale"
);
input(&mut app, "pump_new");
let job = start_preview(&mut app);
let completion = preview_completion(&app, job);
// No intermediate frame mounts the temporary no-approval view. The old
// Scrollable survives even though the new approval has a different id.
let ready = app.update(Message::SourceRenameReady(completion));
assert!(mounted.offset(&app) > 10.);
assert_eq!(mounted.execute(&app, ready).await, 1);
assert_eq!(mounted.offset(&app), 0.);
assert_eq!(evidence(&app), before);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,313 @@
//! Manual replacement + next-layout/highlight evaluator; no GPU or native paint.
//! Child of source_rename_timing_tests, preserving the separate real App test.
use super::*;
use crate::{highlight, views::source_tests::FontLayout};
use iced::advanced::widget::operation::Focusable;
use iced::advanced::{Layout, graphics, layout, renderer, text as shaped, widget::Tree};
use iced::{
Background, Color, Element, Font, Length, Pixels, Point, Rectangle, Size, Transformation,
};
// The same real Paragraph and Editor as FontLayout. During draw, retain only a
// Weak and fixed geometry; inspect glyphs after timing, never in fill_editor.
#[derive(Default)]
struct ObservedFontLayout {
drawn: Option<(graphics::text::editor::Weak, Point, Rectangle)>,
}
impl renderer::Renderer for ObservedFontLayout {
fn start_layer(&mut self, _: Rectangle) {}
fn end_layer(&mut self) {}
fn start_transformation(&mut self, _: Transformation) {}
fn end_transformation(&mut self) {}
fn reset(&mut self, _: Rectangle) {
self.drawn = None;
}
fn fill_quad(&mut self, _: renderer::Quad, _: impl Into<Background>) {}
fn allocate_image(
&mut self,
handle: &iced::advanced::image::Handle,
callback: impl FnOnce(Result<iced::advanced::image::Allocation, iced::advanced::image::Error>)
+ Send
+ 'static,
) {
renderer::Renderer::allocate_image(&mut FontLayout, handle, callback);
}
}
impl shaped::Renderer for ObservedFontLayout {
type Font = Font;
type Paragraph = <FontLayout as shaped::Renderer>::Paragraph;
type Editor = <FontLayout as shaped::Renderer>::Editor;
const ICON_FONT: Font = <FontLayout as shaped::Renderer>::ICON_FONT;
const CHECKMARK_ICON: char = <FontLayout as shaped::Renderer>::CHECKMARK_ICON;
const ARROW_DOWN_ICON: char = <FontLayout as shaped::Renderer>::ARROW_DOWN_ICON;
const SCROLL_UP_ICON: char = <FontLayout as shaped::Renderer>::SCROLL_UP_ICON;
const SCROLL_DOWN_ICON: char = <FontLayout as shaped::Renderer>::SCROLL_DOWN_ICON;
const SCROLL_LEFT_ICON: char = <FontLayout as shaped::Renderer>::SCROLL_LEFT_ICON;
const SCROLL_RIGHT_ICON: char = <FontLayout as shaped::Renderer>::SCROLL_RIGHT_ICON;
const ICED_LOGO: char = <FontLayout as shaped::Renderer>::ICED_LOGO;
fn default_font(&self) -> Font {
shaped::Renderer::default_font(&FontLayout)
}
fn default_size(&self) -> Pixels {
shaped::Renderer::default_size(&FontLayout)
}
fn fill_paragraph(&mut self, _: &Self::Paragraph, _: Point, _: Color, _: Rectangle) {}
fn fill_editor(&mut self, editor: &Self::Editor, position: Point, _: Color, clip: Rectangle) {
self.drawn = Some((editor.downgrade(), position, clip));
}
fn fill_text(&mut self, _: shaped::Text, _: Point, _: Color, _: Rectangle) {}
}
type Content = text_editor::Content<ObservedFontLayout>;
const HOST: Size = Size::new(640., 350.);
fn view(editor: &Content, source: Arc<str>) -> Element<'_, (), iced::Theme, ObservedFontLayout> {
text_editor(editor)
.on_action(|_| ())
.font(Font::MONOSPACE)
.size(14)
.padding(16)
.height(Length::Fill)
.highlight_with::<highlight::ArcadiaHighlighter>(source, highlight::format)
.into()
}
fn check_text(editor: &Content, expected: &str, cursor: text_editor::Cursor) {
assert_eq!(editor.text(), expected);
assert_eq!(editor.cursor(), cursor);
let lines: Vec<_> = expected.split('\n').collect();
assert_eq!(editor.line_count(), lines.len());
for (index, part) in lines.iter().enumerate() {
let (text, ending) = if index + 1 == lines.len() {
(*part, text_editor::LineEnding::None)
} else if let Some(text) = part.strip_suffix('\r') {
(text, text_editor::LineEnding::CrLf)
} else {
(*part, text_editor::LineEnding::Lf)
};
let actual = editor.line(index).unwrap();
assert_eq!(actual.text, text);
assert_eq!(actual.ending, ending);
}
}
fn check_draw(renderer: &ObservedFontLayout, cursor: text_editor::Cursor, alias: &str) {
let (weak, position, clip) = renderer.drawn.as_ref().expect("real editor draw");
let editor = weak.upgrade().expect("drawn editor is still live");
let buffer = editor.buffer();
assert_eq!(weak.bounds, Size::new(608., 318.));
assert_eq!(buffer.size(), (Some(608.), Some(318.)));
assert_eq!(buffer.metrics().font_size, 14.);
assert_eq!(
buffer.scroll().horizontal,
0.,
"fixture origin fits the viewport"
);
let start = cursor.position;
let end = cursor.selection.expect("approved alias selection");
assert_eq!(start.line, end.line);
assert_eq!(end.column - start.column, alias.len());
let line = &buffer.lines[start.line];
assert_eq!(&line.text()[start.column..end.column], alias);
let color = graphics::text::to_color(Color::from_rgb8(20, 93, 139));
let font = graphics::text::to_attributes(Font::MONOSPACE);
for byte in start.column..end.column {
let attrs = line.attrs_list().get_span(byte);
assert_eq!(
attrs.color_opt,
Some(color),
"accepted alias syntax attributes"
);
assert_eq!(attrs.family, font.family);
}
let mut covered = vec![false; alias.len()];
for run in buffer.layout_runs().filter(|run| run.line_i == start.line) {
for glyph in run.glyphs {
let from = glyph.start.max(start.column);
let to = glyph.end.min(end.column);
if from >= to {
continue;
}
assert_eq!(glyph.color_opt, Some(color), "drawn alias glyph color");
let x = position.x + glyph.x + glyph.x_offset * glyph.font_size;
let y = position.y + run.line_top;
assert!(x >= clip.x - 0.5 && x + glyph.w <= clip.x + clip.width + 0.5);
assert!(y + run.line_height > clip.y && y < clip.y + clip.height);
covered[from - start.column..to - start.column].fill(true);
}
}
assert!(
covered.into_iter().all(|seen| seen),
"entire alias has visible shaped glyphs"
);
// This temporary strong upgrade is dropped before the next editor mutation.
}
#[derive(Clone, Copy)]
enum Arm {
Constructor,
Reuse,
}
impl Arm {
fn name(self) -> &'static str {
match self {
Self::Constructor => "with_text",
Self::Reuse => "same_line_reuse",
}
}
fn phases(self) -> [&'static str; 4] {
match self {
Self::Constructor => [
"constructor_replace_origin",
"constructor_next_layout",
"constructor_highlight_draw",
"constructor_combined",
],
Self::Reuse => [
"reuse_replace_origin",
"reuse_next_layout",
"reuse_highlight_draw",
"reuse_combined",
],
}
}
}
fn trial(
fixture: &Fixture,
cursor: text_editor::Cursor,
arm: Arm,
trial: usize,
samples: &mut Samples,
) {
let before = &fixture.bundle.files[ORIGIN];
let after = &fixture.expected_bundle.files[ORIGIN];
let mut editor = Content::with_text(before);
editor.move_to(fixture.cursor);
let mut renderer = ObservedFontLayout::default();
let theme = iced::Theme::Light;
let defaults = renderer::Style::default();
let viewport = Rectangle::with_size(HOST);
let limits = layout::Limits::new(Size::ZERO, HOST);
let mut tree = {
let mut widget = view(&editor, Arc::from(before.as_str()));
let mut tree = Tree::new(widget.as_widget());
let node = widget.as_widget_mut().layout(&mut tree, &renderer, &limits);
tree.state
.downcast_mut::<text_editor::State<highlight::ArcadiaHighlighter>>()
.focus();
widget.as_widget().draw(
&tree,
&mut renderer,
&theme,
&defaults,
Layout::new(&node),
iced::mouse::Cursor::Unavailable,
&viewport,
);
tree
};
check_text(&editor, before, fixture.cursor);
check_draw(&renderer, fixture.cursor, OLD);
// No recorder Weak/Strong from setup may perturb replacement ownership.
renderer.drawn = None;
let next_source: Arc<str> = Arc::from(after.as_str());
// Only normal operations and four timestamps occur between start and end.
// Source/model oracles, logging and recorder glyph inspection are outside.
let started = Instant::now();
let replaced = match arm {
Arm::Constructor => {
editor = Content::with_text(after);
true
}
Arm::Reuse => super::super::editor_patch::replace(&mut editor, before, after),
};
editor.move_to(cursor);
let replaced_at = Instant::now();
let mut widget = view(&editor, next_source);
let node = widget.as_widget_mut().layout(&mut tree, &renderer, &limits);
let laid_out_at = Instant::now();
widget.as_widget().draw(
&tree,
&mut renderer,
&theme,
&defaults,
Layout::new(&node),
iced::mouse::Cursor::Unavailable,
&viewport,
);
let drawn_at = Instant::now();
drop(widget);
assert!(replaced, "reuse must not silently time a fallback/refusal");
check_text(&editor, after, cursor);
check_draw(&renderer, cursor, NEW);
renderer.drawn = None;
for (phase, duration) in arm.phases().into_iter().zip([
replaced_at.duration_since(started),
laid_out_at.duration_since(replaced_at),
drawn_at.duration_since(laid_out_at),
drawn_at.duration_since(started),
]) {
println!(
"{}",
serde_json::json!({
"record": "editor_layout_timing", "arm": arm.name(), "phase": phase,
"trial": trial, "warmup": trial == 0,
"elapsed_ns": duration.as_nanos().to_string(),
"elapsed_ms": duration.as_secs_f64() * 1000.0,
})
);
if trial != 0 {
samples.0.entry(phase).or_default().push(duration);
}
}
}
#[test]
#[ignore = "manual Windows dev/debug editor replacement + layout/highlight trial; run alone with --ignored --nocapture --test-threads=1"]
fn accepted_release1_constructor_vs_reuse_through_next_highlight() {
let fixture = Fixture::load();
// Resolve the exact production approval and verify full Project/source once,
// outside all intervals. The actual App Confirm evaluator remains separate.
let cursor = {
let app = fixture.app();
let target = resolve(&app, &app.rename_context());
let prepared = app
.document
.alias_rename_request(target.id, NEW.into())
.unwrap()
.prepare()
.unwrap();
fixture.check_candidate(&prepared);
prepare_approval(prepared, &target, ORIGIN).unwrap().cursor
};
println!(
"{}",
serde_json::json!({
"record": "editor_layout_fixture", "host_width": HOST.width, "host_height": HOST.height,
"font": "MONOSPACE", "font_size": 14, "padding": 16, "height": "Fill",
"active_file": ORIGIN, "before_bytes": fixture.bundle.files[ORIGIN].len(),
"after_bytes": fixture.expected_bundle.files[ORIGIN].len(), "warmups_per_arm": 1,
"measured_trials_per_arm": 5, "debug_assertions": cfg!(debug_assertions),
"scope": "real editor replacement, retained Tree layout and Widget draw/highlight; no GPU, native paint or App Confirm",
})
);
let mut samples = Samples::default();
for index in 0..=5 {
let arms = if index % 2 == 0 {
[Arm::Constructor, Arm::Reuse]
} else {
[Arm::Reuse, Arm::Constructor]
};
println!(
"{}",
serde_json::json!({"record": "editor_layout_order", "trial": index, "first": arms[0].name()})
);
for arm in arms {
trial(&fixture, cursor, arm, index, &mut samples);
}
}
samples.report();
}
@@ -0,0 +1,347 @@
//! Manual timing through the real Document and App paths. No disk writes,
//! executor polling, layout, GPU work or first-paint measurement occurs here.
//! Register as a test child of app::source_rename to use its actual worker helpers.
use super::*;
use crate::source_workspace::Workspace;
use oa_core::source_project::SourceBundle;
use std::{
collections::BTreeMap,
path::PathBuf,
time::{Duration, Instant},
};
#[cfg(debug_assertions)]
#[path = "source_rename_layout_timing_tests.rs"]
mod layout_timing_tests;
const OLD: &str = "oa_restore_work";
const NEW: &str = "oa_restore_pressure";
const DECLARATIONS: &str = "oa/activities/activity_oa_restore_work.arcadia";
const ORIGIN: &str = "traceability.arcadia";
struct Fixture {
bundle: SourceBundle,
project: Project,
expected_bundle: SourceBundle,
expected_project: Project,
target: Id,
cursor: text_editor::Cursor,
}
impl Fixture {
fn load() -> Self {
// The optional entry selects a parent-pinned copy of this exact fixture,
// not an arbitrary performance generator or a mutable GUI destination.
let entry = std::env::var_os("ARCADIA_RENAME_TIMING_ENTRY")
.map(PathBuf::from)
.unwrap_or_else(|| {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../examples/release1/project.arcadia")
});
let loaded = oa_core::source_files::load_project(&entry, LIMITS).unwrap();
let bundle = loaded.reachable_bundle();
assert_eq!(
bundle.files.len(),
30,
"use the preserved release1 walkthrough"
);
let document = Document::from_bundle(bundle.clone(), LIMITS).unwrap();
assert_eq!(
document.bundle(),
&bundle,
"fixture must need no stabilization/migration"
);
assert!(!document.dirty());
let project = document.project().clone();
let target = Id::parse_str("1b91f8a7-0bdb-514e-b1cd-955658e09927").unwrap();
assert_eq!(project.elements[&target].alias, OLD);
assert!(!project.identities().iter().any(|(_, alias)| *alias == NEW));
let mut expected_project = project.clone();
expected_project.elements.get_mut(&target).unwrap().alias = NEW.into();
// Independent literal source oracle, authored before running the rename.
// Do not replace the alias substring in filenames or the trace's alias.
let mut expected_bundle = bundle.clone();
let declarations = expected_bundle.files.get_mut(DECLARATIONS).unwrap();
assert_eq!(
declarations.matches("oa_activity oa_restore_work ").count(),
1
);
assert_eq!(declarations.matches("parent @oa_restore_work;").count(), 4);
*declarations = declarations
.replace(
"oa_activity oa_restore_work ",
"oa_activity oa_restore_pressure ",
)
.replace("parent @oa_restore_work;", "parent @oa_restore_pressure;");
let traces = expected_bundle.files.get_mut(ORIGIN).unwrap();
assert_eq!(traces.matches("oa @oa_restore_work;").count(), 1);
*traces = traces.replace("oa @oa_restore_work;", "oa @oa_restore_pressure;");
let source = &bundle.files[ORIGIN];
let start = source.rfind("@oa_restore_work;").unwrap() + 1;
let position = |offset| {
let prefix = &source[..offset];
text_editor::Position {
line: prefix.bytes().filter(|byte| *byte == b'\n').count(),
column: prefix
.rsplit_once('\n')
.map_or(prefix.len(), |(_, tail)| tail.len()),
}
};
let cursor = text_editor::Cursor {
position: position(start),
selection: Some(position(start + OLD.len())),
};
assert!(nav::exact_cursor(source, cursor));
println!(
"{}",
serde_json::json!({
"record": "fixture", "entry": entry, "reachable_files": bundle.files.len(),
"source_bytes": bundle.files.values().map(String::len).sum::<usize>(),
"identities": project.identities().len(), "active_file": ORIGIN,
"active_file_bytes": source.len(), "old": OLD, "new": NEW,
"warmups": 1, "measured_trials": 5, "debug_assertions": cfg!(debug_assertions),
"scope": "real worker helpers, guarded Document commit, App sync and Confirm update; no task polling or rendering"
})
);
Self {
bundle,
project,
expected_bundle,
expected_project,
target,
cursor,
}
}
fn app(&self) -> App {
let mut app = App::with_project(Project::empty());
app.document = Document::from_bundle(self.bundle.clone(), LIMITS).unwrap();
app.source_workspace = Workspace::new(app.document.bundle(), true);
app.source_workspace.active = ORIGIN.into();
app.selected = app.project().id;
app.page = Page::Text;
app.sync();
app.source_editor.move_to(self.cursor);
assert_eq!(app.project(), &self.project);
assert_eq!(app.document.bundle(), &self.bundle);
assert_eq!(app.document.revision(), 0);
assert!(!app.document.dirty() && !app.document.can_undo() && !app.document.can_redo());
assert!(app.rename_admission().is_ok());
app
}
fn check_candidate(&self, prepared: &PreparedAliasRename) {
assert!(prepared.changed());
assert_eq!(prepared.before().bundle, self.bundle);
assert_eq!(prepared.before().decoded.project, self.project);
assert_eq!(prepared.after().bundle, self.expected_bundle);
assert_eq!(prepared.after().decoded.project, self.expected_project);
}
fn check_adopted(&self, app: &mut App, candidate_address: *const CompiledSourceProject) {
assert!(
std::ptr::eq(app.document.compiled(), candidate_address),
"adopt exact candidate allocation"
);
assert_eq!(app.project(), &self.expected_project);
assert_eq!(app.document.bundle(), &self.expected_bundle);
assert_eq!(app.source_workspace.bundle(), self.expected_bundle);
assert_eq!(app.source_editor.text(), self.expected_bundle.files[ORIGIN]);
assert_eq!(app.document.revision(), 1);
assert!(app.document.dirty() && app.document.can_undo() && !app.document.can_redo());
assert!(app.document.undo());
assert_eq!(app.project(), &self.project);
assert_eq!(app.document.bundle(), &self.bundle);
assert!(
!app.document.dirty(),
"live known saved baseline remains authoritative"
);
assert!(
!app.document.can_undo(),
"exactly one preceding model transaction"
);
assert!(app.document.redo());
assert_eq!(app.project(), &self.expected_project);
assert_eq!(app.document.bundle(), &self.expected_bundle);
assert!(std::ptr::eq(app.document.compiled(), candidate_address));
}
}
#[derive(Default)]
struct Samples(BTreeMap<&'static str, Vec<Duration>>);
impl Samples {
fn time<T>(&mut self, phase: &'static str, trial: usize, action: impl FnOnce() -> T) -> T {
let started = Instant::now();
let result = action();
let elapsed = started.elapsed();
// Printing, assertions and dropping the returned value are outside this
// interval. Full Confirm still includes production's own local drops.
println!(
"{}",
serde_json::json!({
"record": "timing", "phase": phase, "trial": trial,
"warmup": trial == 0, "elapsed_ns": elapsed.as_nanos().to_string(),
"elapsed_ms": elapsed.as_secs_f64() * 1000.0
})
);
if trial != 0 {
self.0.entry(phase).or_default().push(elapsed);
}
result
}
fn report(mut self) {
for (phase, values) in &mut self.0 {
assert_eq!(values.len(), 5);
values.sort();
println!(
"{}",
serde_json::json!({
"record": "summary", "phase": phase, "samples": values.len(),
"min_ms": values[0].as_secs_f64() * 1000.0,
"median_ms": values[2].as_secs_f64() * 1000.0,
"max_ms": values[4].as_secs_f64() * 1000.0
})
);
}
}
}
fn resolve(app: &App, context: &Context) -> Target {
let snapshot = app
.with_source_input(|input| query::admit_owned(input, query::Limits::default()))
.unwrap()
.capture()
.unwrap();
let offset = nav::cursor_offset(app.source_workspace.text(), context.begin.cursor).unwrap();
resolve_target(&snapshot, context, offset).unwrap()
}
fn active_job(app: &App) -> Job {
let form = app.source_rename.form.as_ref().unwrap();
let id = form.pending.unwrap();
assert_eq!(app.source_rename.in_flight, Some(id));
Job {
id,
invocation: form.invocation,
generation: form.generation,
context: form.context.clone(),
}
}
fn separate_phases(fixture: &Fixture, samples: &mut Samples, trial: usize) {
let mut app = fixture.app();
let target = resolve(&app, &app.rename_context());
assert_eq!(target.id, fixture.target);
let request = samples
.time("document_request_mint", trial, || {
app.document.alias_rename_request(target.id, NEW.into())
})
.unwrap();
let prepared = samples
.time("worker_document_prepare", trial, || request.prepare())
.unwrap();
fixture.check_candidate(&prepared);
let approval = samples
.time("worker_preview_and_origin", trial, || {
prepare_approval(prepared, &target, ORIGIN)
})
.unwrap();
assert_eq!(approval.preview.files().len(), 2);
assert_eq!(approval.preview.changed_line_count(), 6);
let candidate_address = approval.prepared.after() as *const CompiledSourceProject;
// Same-destination save completion is a legitimate live update after Preview.
app.document.mark_saved(app.document.snapshot());
let changed = samples
.time("document_guarded_commit", trial, || {
app.document.commit_alias_rename(&approval.prepared)
})
.unwrap();
assert!(changed);
samples.time("app_sync", trial, || app.sync());
fixture.check_adopted(&mut app, candidate_address);
}
fn whole_confirm(fixture: &Fixture, samples: &mut Samples, trial: usize) {
let mut app = fixture.app();
let begin = app.source_rename_message();
// These Tasks are deliberately not polled: deterministic worker helpers
// supply the same results through the real readiness messages below.
drop(app.update(begin));
let target_job = active_job(&app);
let target = Arc::new(resolve(&app, &target_job.context));
assert_eq!(target.id, fixture.target);
drop(app.update(Message::SourceRenameReady(Completion {
job: target_job,
payload: Payload::Target(Ok(target.clone())),
})));
let invocation = app.source_rename.form.as_ref().unwrap().invocation;
drop(app.update(Message::SourceRename(Event::Input(invocation, NEW.into()))));
let generation = app.source_rename.form.as_ref().unwrap().generation;
drop(app.update(Message::SourceRename(Event::Preview(
invocation, generation,
))));
let preview_job = active_job(&app);
let prepared = app
.document
.alias_rename_request(target.id, NEW.into())
.unwrap()
.prepare()
.unwrap();
fixture.check_candidate(&prepared);
let approval = Arc::new(prepare_approval(prepared, &target, ORIGIN).unwrap());
drop(target);
let candidate_address = approval.prepared.after() as *const CompiledSourceProject;
let expected_cursor = approval.cursor;
let approval_id = approval.id;
drop(app.update(Message::SourceRenameReady(Completion {
job: preview_job,
payload: Payload::Preview(Ok(approval)),
})));
assert_eq!(
app.source_rename
.form
.as_ref()
.unwrap()
.approval
.as_ref()
.unwrap()
.id,
approval_id
);
app.document.mark_saved(app.document.snapshot());
let confirm = Message::SourceRename(Event::Confirm(invocation, generation, approval_id));
let task = samples.time("app_confirm_update", trial, || app.update(confirm));
samples.time("confirm_returned_task_drop_without_polling", trial, || {
drop(task)
});
assert!(!app.source_rename.open());
assert!(app.source_rename.in_flight.is_none());
assert!(app.source_rename_undo_message().is_some());
assert_eq!(app.source_editor.cursor(), expected_cursor);
fixture.check_adopted(&mut app, candidate_address);
}
#[test]
#[ignore = "manual Windows dev/debug rename latency trial; run alone with --ignored --nocapture --test-threads=1"]
fn accepted_release1_prepare_commit_sync_and_confirm_timing() {
let fixture = Fixture::load();
let mut samples = Samples::default();
for trial in 0..=5 {
println!(
"{}",
serde_json::json!({ "record": "order", "trial": trial,
"warmup": trial == 0, "separate_phases_first": trial % 2 == 0 })
);
if trial % 2 == 0 {
separate_phases(&fixture, &mut samples, trial);
whole_confirm(&fixture, &mut samples, trial);
} else {
whole_confirm(&fixture, &mut samples, trial);
separate_phases(&fixture, &mut samples, trial);
}
}
samples.report();
}
+464
View File
@@ -0,0 +1,464 @@
//! Current draft navigation, isolated from model application and disk discovery.
use super::*;
use crate::source_navigation::{self as nav, query};
use std::sync::atomic::Ordering;
fn admission_notice(error: query::AdmissionError) -> String {
use nav::symbols::{BuildError, InputProblem, Resource};
let (limit, resource) = match error {
query::AdmissionError::Index(BuildError::Limit { limit, resource, .. }) => (limit, resource),
query::AdmissionError::Outline { error, .. } => (error.limit, match error.resource {
language::OutlineResource::SourceBytes => Resource::SourceBytes,
language::OutlineResource::Tokens => Resource::Tokens,
language::OutlineResource::Declarations => Resource::Records,
}),
query::AdmissionError::Index(BuildError::Input { problem, .. }) => return match problem {
InputProblem::NonCanonicalPath | InputProblem::DuplicateOrCaseCollidingPath =>
"Navigation needs distinct relative source paths. Check file names and include paths.".into(),
_ => "Navigation could not verify the current source locations. Correct source errors and try again.".into(),
},
};
let unit = match resource {
Resource::Files => "loaded files",
Resource::SourceBytes => "source bytes",
Resource::PathBytes => "bytes in file paths",
Resource::Tokens => "source tokens",
Resource::Records => "declarations and references",
};
format!(
"Navigation reached its limit of {limit} {unit}. Reduce the loaded source size and try again."
)
}
impl App {
pub fn source_symbol_context(&self) -> nav::SymbolContext {
nav::SymbolContext {
session: self.source_workspace.session(),
path: self.source_workspace.active.clone(),
}
}
pub fn source_symbol_message(&self, event: nav::SymbolEvent) -> Message {
Message::SourceSymbols(self.source_symbol_context(), event)
}
pub fn source_find_close_message(&self) -> Message {
Message::SourceFindClose(self.source_symbol_context(), self.source_find_instance)
}
pub fn source_key(&self) -> query::SnapshotKey {
query::SnapshotKey {
workspace: self.source_workspace.session(),
revision: self.source_workspace.revision(),
}
}
pub(super) fn with_source_input<T>(&self, use_input: impl FnOnce(query::Input<'_>) -> T) -> T {
let files: Vec<_> = self
.source_workspace
.files
.iter()
.map(|(path, buffer)| query::DraftFile {
path,
text: &buffer.text,
})
.collect();
let accepted = self.document.bundle();
let validated: Vec<_> = accepted
.files
.iter()
.map(|(path, text)| query::DraftFile { path, text })
.collect();
use_input(query::Input {
key: self.source_key(),
entry: &self.source_workspace.entry,
files: &files,
applied: self.source_workspace.applied,
validation: self
.source_workspace
.applied
.then_some(query::ValidatedSources {
entry: &accepted.entry,
files: &validated,
}),
})
}
pub(super) fn source_snapshot_matches(&self, snapshot: &query::Snapshot) -> bool {
snapshot.key() == self.source_key()
&& self.with_source_input(|input| snapshot.matches(input))
}
pub fn source_navigation_available(&self) -> bool {
self.page == Page::Text
&& !self.source_rename.open()
&& !self.busy
&& self.pending.is_none()
&& self.file_prompt.is_none()
&& !self.delete_pending
&& self.workflow.is_none()
&& !self.hosted.visible
&& self.model_menu.is_none()
&& self.architecture.is_none()
&& !self.behavior.has_pending()
}
/// Mounted widget IDs change when another interaction supersedes a reveal.
/// A queued focus operation therefore cannot find a subsequently reused editor.
pub fn source_editor_id(&self) -> iced::widget::Id {
iced::widget::Id::from(format!(
"source-editor-{}-{}-{}",
self.source_workspace.session(),
self.source_workspace.active,
self.source_symbols.interaction
))
}
pub fn source_reveal_ticket(&self) -> Option<Id> {
self.source_symbols
.reveal
.as_ref()
.map(|reveal| reveal.ticket)
}
pub(super) fn source_interaction(&mut self) {
self.source_symbols.interaction = Id::new_v4();
self.source_symbols.request = None;
self.source_symbols.reveal = None;
self.source_jump = None;
}
pub(super) fn queue_source_reveal(&mut self, cursor: text_editor::Cursor, select_line: bool) {
self.source_jump = Some(cursor);
self.source_select_line = select_line;
self.source_symbols.reveal = Some(nav::Reveal {
ticket: Id::new_v4(),
interaction: self.source_symbols.interaction,
raw_interaction: self.source_symbols.raw_interaction.load(Ordering::SeqCst),
snapshot: self.source_key(),
path: self.source_workspace.active.clone(),
});
}
pub(super) fn restore_source_editor_focus(&mut self) {
let cursor = self.source_editor.cursor();
if self.source_navigation_available()
&& nav::exact_cursor(self.source_workspace.text(), cursor)
{
self.queue_source_reveal(cursor, false);
}
}
pub(super) fn source_viewport(&mut self, ticket: Option<Id>) -> Task<Message> {
let Some(reveal) = &self.source_symbols.reveal else {
return Task::none();
};
if Some(reveal.ticket) != ticket
|| reveal.interaction != self.source_symbols.interaction
|| !nav::interaction::is_current(
&self.source_symbols.raw_interaction,
reveal.raw_interaction,
)
|| reveal.snapshot != self.source_key()
|| reveal.path != self.source_workspace.active
|| !self.source_navigation_available()
{
return Task::none();
}
let raw_interaction = reveal.raw_interaction;
self.source_symbols.reveal = None;
if let Some(cursor) = self.source_jump.take() {
if !nav::exact_cursor(self.source_workspace.text(), cursor) {
return Task::none();
}
self.source_editor.move_to(cursor);
if self.source_select_line && cursor.selection.is_none() {
self.source_editor.perform(text_editor::Action::SelectLine);
}
return nav::interaction::guarded_focus(
self.source_editor_id(),
self.source_symbols.raw_interaction.clone(),
raw_interaction,
);
}
Task::none()
}
pub(super) fn source_symbol_event(&mut self, event: nav::SymbolEvent) -> Task<Message> {
if !self.source_navigation_available() {
return Task::none();
}
match event {
nav::SymbolEvent::Close => {
self.source_symbols.open = false;
self.source_symbols.results = None;
self.source_symbols.notice = None;
}
nav::SymbolEvent::Back => {
self.source_symbol_back();
// A successful Back needs no empty results panel. Retain an
// already open panel, or reveal an actionable return notice.
self.source_symbols.open |= self.source_symbols.notice.is_some();
}
nav::SymbolEvent::Choose {
stamp,
reference,
index,
} => {
let Some(results) = self.source_symbols.results.clone() else {
return Task::none();
};
if results.stamp != stamp
|| stamp.snapshot != self.source_key()
|| self
.source_symbols
.cache
.as_ref()
.is_none_or(|cache| !self.source_snapshot_matches(cache))
{
self.source_symbols.notice =
Some("Source changed. Run navigation again for current locations.".into());
return Task::none();
}
let destination = if reference {
results
.references
.get(index)
.map(|row| (&row.path, row.position, row.end_position))
} else {
results
.definitions
.get(index)
.map(|row| (&row.path, row.position, row.end_position))
};
if let Some((path, start, end)) = destination {
self.source_symbol_jump(path, start, end);
}
}
nav::SymbolEvent::Query(action) => return self.start_source_query(action),
}
Task::none()
}
fn start_source_query(&mut self, action: query::Action) -> Task<Message> {
self.source_symbols.open = true;
if !nav::interaction::is_current(
&self.source_symbols.raw_interaction,
self.source_symbols.raw_interaction.load(Ordering::SeqCst),
) {
self.source_symbols.notice = Some("Reopen this workspace to reset navigation.".into());
return Task::none();
}
if self.source_symbols.in_flight.is_some() {
self.source_symbols.notice = Some("Navigation is finishing. Try again shortly.".into());
return Task::none();
}
let cursor = self.source_editor.cursor();
let Some(offset) = nav::cursor_offset(self.source_workspace.text(), cursor) else {
self.source_symbols.notice =
Some("Place the cursor on an alias or its @ reference.".into());
return Task::none();
};
self.source_symbols.serial = match self.source_symbols.serial.checked_add(1) {
Some(serial) => serial,
None => {
self.source_workspace.reset_navigation_session();
self.source_symbols.back.clear();
self.source_symbols.cache = None;
0
}
};
let request = nav::Request {
job: Id::new_v4(),
interaction: self.source_symbols.interaction,
raw_interaction: self.source_symbols.raw_interaction.load(Ordering::SeqCst),
stamp: query::QueryStamp {
snapshot: self.source_key(),
serial: self.source_symbols.serial,
},
path: self.source_workspace.active.clone(),
offset,
cursor,
action,
};
let cache = self
.source_symbols
.cache
.as_ref()
.filter(|cache| self.source_snapshot_matches(cache))
.cloned();
let input = if cache.is_none() {
match self
.with_source_input(|input| query::admit_owned(input, query::Limits::default()))
{
Ok(input) => Some(input),
Err(error) => {
self.source_symbols.notice = Some(admission_notice(error));
return Task::none();
}
}
} else {
None
};
self.source_symbols.in_flight = Some(request.job);
self.source_symbols.request = Some(request.clone());
self.source_symbols.results = None;
self.source_symbols.notice = None;
Task::perform(
async move {
let worker_request = request.clone();
let result = tokio::task::spawn_blocking(move || {
let snapshot = match cache {
Some(cache) => cache,
None => Arc::new(
input
.expect("admitted input for uncached request")
.capture()
.map_err(admission_notice)?,
),
};
let results = snapshot
.query(query::Query {
stamp: worker_request.stamp,
path: &worker_request.path,
byte_offset: worker_request.offset,
action: worker_request.action,
})
.map_err(|error| match error {
query::QueryError::ResultEnvelopeLimit => "These result details exceed the display limit. Try literal Find for this alias.".to_owned(),
_ => "Navigation could not verify this location. Place the cursor on an alias and try again.".to_owned(),
})?;
Ok((snapshot, Arc::new(results)))
})
.await
.unwrap_or_else(|error| Err(format!("Navigation task failed: {error}")));
nav::Completion { request, result }
},
Message::SourceSymbolsReady,
)
}
pub(super) fn source_symbols_ready(&mut self, completion: nav::Completion) -> Task<Message> {
let request = completion.request;
if self.source_symbols.in_flight != Some(request.job) {
return Task::none();
}
self.source_symbols.in_flight = None;
let wanted = self
.source_symbols
.request
.take()
.is_some_and(|current| current.job == request.job)
&& request.interaction == self.source_symbols.interaction
&& request.stamp.snapshot == self.source_key()
&& nav::interaction::is_current(
&self.source_symbols.raw_interaction,
request.raw_interaction,
)
&& request.path == self.source_workspace.active
&& request.cursor == self.source_editor.cursor()
&& self.source_navigation_available();
if !wanted {
return Task::none();
}
match completion.result {
Ok((snapshot, results)) if self.source_snapshot_matches(&snapshot) => {
self.source_symbols.cache = Some(snapshot);
self.source_symbols.results = Some(results.clone());
if results.disposition == query::Disposition::Direct
&& let Some(row) = results.definitions.first()
{
self.source_symbol_jump(&row.path, row.position, row.end_position);
}
}
Ok(_) => {
self.source_symbols.notice = Some("Source changed. Run navigation again.".into())
}
Err(error) => self.source_symbols.notice = Some(error),
}
Task::none()
}
fn source_symbol_jump(&mut self, path: &str, start: query::Position, end: query::Position) {
let cursor = text_editor::Cursor {
position: text_editor::Position {
line: start.line,
column: start.byte_column,
},
selection: Some(text_editor::Position {
line: end.line,
column: end.byte_column,
}),
};
if self
.source_workspace
.files
.get(path)
.is_none_or(|buffer| !nav::exact_cursor(&buffer.text, cursor))
{
self.source_symbols.notice =
Some("That source location is no longer available. Run navigation again.".into());
return;
}
if let Some(buffer) = self
.source_workspace
.files
.get(&self.source_workspace.active)
{
let origin = nav::HistoryEntry {
session: self.source_workspace.session(),
path: self.source_workspace.active.clone(),
generation: buffer.generation(),
cursor: self.source_editor.cursor(),
};
self.source_symbols
.back
.retain(|entry| entry.session == origin.session);
if self.source_symbols.back.len() == 64 {
self.source_symbols.back.remove(0);
}
self.source_symbols.back.push(origin);
}
self.source_workspace
.switch(path, self.source_editor.cursor());
self.show_source_file(false);
self.queue_source_reveal(cursor, false);
}
fn source_symbol_back(&mut self) {
while let Some(origin) = self.source_symbols.back.pop() {
if origin.session != self.source_workspace.session() {
continue;
}
let Some(buffer) = self.source_workspace.files.get(&origin.path) else {
self.source_symbols.notice = Some("The previous file is no longer loaded.".into());
return;
};
let unchanged = origin.generation == buffer.generation();
let cursor = if unchanged {
origin.cursor
} else if origin.path == self.source_workspace.active {
self.source_editor.cursor()
} else {
buffer.cursor
};
if !nav::exact_cursor(&buffer.text, cursor) {
self.source_symbols.notice = Some(
"The previous location changed. Open the file to choose a current position."
.into(),
);
return;
}
self.source_workspace
.switch(&origin.path, self.source_editor.cursor());
self.show_source_file(false);
self.queue_source_reveal(cursor, false);
self.source_symbols.notice =
(!unchanged).then(|| "This draft changed; its current cursor was restored.".into());
return;
}
self.source_symbols.notice = Some("No previous source location in this workspace.".into());
}
}
#[cfg(test)]
mod tests;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+35 -5
View File
@@ -10,6 +10,10 @@ use std::{fmt, sync::Arc};
const HISTORY_LIMIT: usize = 100;
const HISTORY_BYTES: usize = 32 * 1024 * 1024;
#[path = "document_alias_rename.rs"]
mod alias_rename;
pub use alias_rename::PreparedAliasRename;
struct HistoryEntry {
snapshot: Arc<CompiledSourceProject>,
bytes: usize,
@@ -91,11 +95,13 @@ impl From<Vec<SourceDiagnostic>> for DocumentError {
}
pub struct Document {
// Distinguishes equal accepted snapshots belonging to different documents.
alias_owner: Arc<()>,
current: Arc<CompiledSourceProject>,
past: Vec<HistoryEntry>,
future: Vec<HistoryEntry>,
current_bytes: usize,
saved: Arc<SourceBundle>,
saved: Option<Arc<SourceBundle>>,
revision: u64,
view_index: std::cell::OnceCell<oa_core::view_options::ViewIndex>,
limits: ProjectLimits,
@@ -121,11 +127,12 @@ impl Document {
let current = Arc::new(source_project::compile_bundle(&bundle, limits)?);
let current_bytes = estimated_bytes(&current);
Ok(Self {
alias_owner: Arc::new(()),
current,
current_bytes,
past: Vec::new(),
future: Vec::new(),
saved: Arc::new(bundle),
saved: Some(Arc::new(bundle)),
revision: 0,
view_index: Default::default(),
limits,
@@ -156,7 +163,7 @@ impl Document {
}
pub fn dirty(&self) -> bool {
self.recovered_unsaved || self.bundle() != self.saved.as_ref()
self.recovered_unsaved || self.saved.as_deref() != Some(self.bundle())
}
/// Recovered work is a detached copy until explicitly saved by its user.
@@ -181,10 +188,24 @@ impl Document {
/// Records the bytes actually saved, even when later edits remain current.
/// The I/O adapter owns document identity and save completion ordering.
pub fn mark_saved(&mut self, snapshot: Arc<CompiledSourceProject>) {
self.saved = Arc::new(snapshot.bundle.clone());
self.saved = Some(Arc::new(snapshot.bundle.clone()));
self.recovered_unsaved = false;
}
/// Bind an installed or recovered repair destination to source read there.
/// These bytes may be invalid or differ from the retained accepted model,
/// but must replace the previous disk baseline. Accepted history is retained;
/// applying or undoing to old saved content does not save this destination.
pub(crate) fn bind_repair_baseline(&mut self, source: SourceBundle) {
self.saved = Some(Arc::new(source));
}
/// Recovery changed the current destination, but its source could not be
/// reloaded. No accepted or historical snapshot is known to be saved there.
pub(crate) fn invalidate_saved_baseline(&mut self) {
self.saved = None;
}
/// Check a source Save as before writing any files. A retained included file
/// must never be displaced by the new entry, including on a later Undo.
pub fn check_save_entry(&self, entry: &str) -> Result<(), DocumentError> {
@@ -380,8 +401,17 @@ impl Document {
return false;
}
let bytes = estimated_bytes(&compiled);
self.commit_snapshot(Arc::new(compiled), bytes)
}
// Only validated internal paths supply a changed snapshot and its exact
// estimate. The ordinary commit wrapper checks bundle inequality; the alias
// path checks its private changed flag and exact accepted-snapshot authority.
// Alias preparation shares this algorithm while retaining the live save and
// history state, and does not clone/recompile the candidate on adoption.
fn commit_snapshot(&mut self, compiled: Arc<CompiledSourceProject>, bytes: usize) -> bool {
self.past.push(HistoryEntry {
snapshot: std::mem::replace(&mut self.current, Arc::new(compiled)),
snapshot: std::mem::replace(&mut self.current, compiled),
bytes: std::mem::replace(&mut self.current_bytes, bytes),
});
self.future.clear();
@@ -0,0 +1,233 @@
//! Alias-only worker preparation and guarded adoption. Public compiled DTOs do
//! not authorize adoption; only this module can mint a prepared rename.
use super::*;
use std::collections::BTreeMap;
/// A pinned intent minted by its owning Document. Move it to a worker and call
/// `prepare`; preparation has no access to the live Document or its histories.
#[derive(Debug)]
pub struct AliasRenameRequest {
owner: Arc<()>,
before: Arc<CompiledSourceProject>,
revision: u64,
limits: ProjectLimits,
target: Id,
old_alias: String,
new_alias: String,
}
#[derive(Debug)]
struct PreparedData {
request: AliasRenameRequest,
after: Arc<CompiledSourceProject>,
before_bytes: usize,
after_bytes: usize,
changed: bool,
}
/// Immutable, Clone-compatible transport for preview and approval. Neither
/// mutable candidate access nor deserialization can manufacture this authority.
#[derive(Debug, Clone)]
pub struct PreparedAliasRename(Arc<PreparedData>);
impl PreparedAliasRename {
pub fn before(&self) -> &CompiledSourceProject {
&self.0.request.before
}
pub fn after(&self) -> &CompiledSourceProject {
&self.0.after
}
pub fn target(&self) -> Id {
self.0.request.target
}
pub fn old_alias(&self) -> &str {
&self.0.request.old_alias
}
pub fn new_alias(&self) -> &str {
&self.0.request.new_alias
}
pub fn revision(&self) -> u64 {
self.0.request.revision
}
pub fn changed(&self) -> bool {
self.0.changed
}
}
fn refusal(message: &str) -> DocumentError {
ModelError(message.into()).into()
}
fn check_history_capacity(before_bytes: usize, after_bytes: usize) -> Result<(), DocumentError> {
if before_bytes.saturating_add(after_bytes) > HISTORY_BYTES {
return Err(refusal(
"This rename exceeds the model Undo budget. No rename was applied.",
));
}
Ok(())
}
impl Document {
pub fn alias_rename_request(
&self,
target: Id,
replacement: String,
) -> Result<AliasRenameRequest, DocumentError> {
if self.revision == u64::MAX {
return Err(refusal(
"The document revision is exhausted. Reopen before renaming.",
));
}
let old_alias = self
.project()
.identities()
.into_iter()
.find_map(|(id, alias)| (id == target).then(|| alias.to_owned()))
.ok_or_else(|| refusal("The alias target is no longer present."))?;
// A candidate has a nonzero estimate. Avoid expensive preparation when
// even the current snapshot leaves no room for its immediate Undo.
if old_alias != replacement && self.current_bytes >= HISTORY_BYTES {
return Err(refusal(
"This rename exceeds the model Undo budget. No rename was applied.",
));
}
Ok(AliasRenameRequest {
owner: self.alias_owner.clone(),
before: self.current.clone(),
revision: self.revision,
limits: self.limits,
target,
old_alias,
new_alias: replacement,
})
}
/// App must separately consume its current approval and check workspace,
/// invocation and draft freshness. This checks accepted Document authority.
pub fn commit_alias_rename(
&mut self,
prepared: &PreparedAliasRename,
) -> Result<bool, DocumentError> {
let data = &prepared.0;
let request = &data.request;
if self.revision == u64::MAX
|| self.revision != request.revision
|| !Arc::ptr_eq(&self.alias_owner, &request.owner)
|| !Arc::ptr_eq(&self.current, &request.before)
{
return Err(refusal(
"This rename preview is stale. Preview the current alias again.",
));
}
if !data.changed {
return Ok(false);
}
if self.current_bytes != data.before_bytes {
return Err(refusal(
"The rename history estimate is stale. Preview again.",
));
}
check_history_capacity(self.current_bytes, data.after_bytes)?;
Ok(self.commit_snapshot(data.after.clone(), data.after_bytes))
}
}
impl AliasRenameRequest {
/// Run on the preparation worker. The typed command and source updater are
/// the only candidate construction path, followed by alias-only invariants.
pub fn prepare(self) -> Result<PreparedAliasRename, DocumentError> {
let before_project = &self.before.decoded.project;
let candidate = prepare_command(
before_project,
&Command::SetAlias(self.target, self.new_alias.clone()),
)?;
let mut expected = before_project.clone();
assign_expected_alias(&mut expected, self.target, &self.new_alias)?;
let identities: BTreeMap<_, _> = before_project
.identities()
.into_iter()
.map(|(id, _)| (id, id))
.collect();
if candidate.project != expected || candidate.identity_map != identities {
return Err(refusal(
"Alias preparation changed unrelated model data or identities.",
));
}
let after = source_project::update_bundle_with_identity_map(
&self.before,
&candidate.project,
&candidate.identity_map,
self.limits,
)?;
let before = &self.before;
if after.decoded.project != expected
|| before.bundle.entry != after.bundle.entry
|| !before.bundle.files.keys().eq(after.bundle.files.keys())
|| before.index.lexical_owners != after.index.lexical_owners
|| !before
.index
.declarations
.iter()
.map(|(id, loc)| (id, &loc.path))
.eq(after
.index
.declarations
.iter()
.map(|(id, loc)| (id, &loc.path)))
{
return Err(refusal(
"Alias preparation changed source membership or ownership.",
));
}
let changed = before.bundle != after.bundle;
let before_bytes = estimated_bytes(before);
let after_bytes = estimated_bytes(&after);
if changed {
check_history_capacity(before_bytes, after_bytes)?;
}
Ok(PreparedAliasRename(Arc::new(PreparedData {
request: self,
after: Arc::new(after),
before_bytes,
after_bytes,
changed,
})))
}
}
// Independent full-model expectation: SetAlias may change exactly one header
// field, across every supported identity family. Do not reuse command execution
// to derive the expected result, which would hide collateral command changes.
fn assign_expected_alias(project: &mut Project, id: Id, alias: &str) -> Result<(), DocumentError> {
if project.id == id {
project.alias = alias.to_owned();
} else if let Some(record) = project.elements.get_mut(&id) {
record.alias = alias.to_owned();
} else if let Some(record) = project.relations.get_mut(&id) {
record.alias = alias.to_owned();
} else if let Some(record) = project.diagrams.get_mut(&id) {
record.alias = alias.to_owned();
} else if let Some(record) = project.artifact_links.get_mut(&id) {
record.alias = alias.to_owned();
} else if let Some(record) = project.traces.get_mut(&id) {
record.alias = alias.to_owned();
} else {
project
.diagrams
.values_mut()
.find_map(|diagram| diagram.nodes.get_mut(&id))
.ok_or_else(|| refusal("The alias target is no longer present."))?
.alias = alias.to_owned();
}
Ok(())
}
#[cfg(test)]
#[path = "document_alias_rename_tests.rs"]
mod tests;
@@ -0,0 +1,459 @@
use super::*;
fn fixture() -> Document {
let bundle = SourceBundle {
entry: "project.arcadia".into(),
files: BTreeMap::from([
("project.arcadia".into(), r#"arcadia 7;
project mission "Испытание" id "10000000-0000-4000-8000-000000000001" {
include "work.arcadia"; include "views.arcadia";
}
"#.replace('\n', "\r\n")),
("work.arcadia".into(), r#"// @assess and assess are explanatory prose.
oa_activity assess "Оценка\u0020ущерба" id "10000000-0000-4000-8000-000000000002" { description "Keep @assess and assess"; }
oa_activity assist "Оценка\u0020ущерба" id "10000000-0000-4000-8000-000000000003" { parent @ // owner evidence
assess; }
sa_function service "Service" id "10000000-0000-4000-8000-000000000004" {}
interaction transfer "Transfer" id "10000000-0000-4000-8000-000000000005" { source @assess; target @assist; }
trace review "Reviewed correspondence" id "10000000-0000-4000-8000-000000000006" { oa @assess; sa @service; kind Refinement; baseline { oa { name "Old assess"; description "@assess"; }; sa { name "Old service"; description "Kept"; }; }; }
artifact evidence "Evidence" id "10000000-0000-4000-8000-000000000007" { owner @review; uri "docs/assess.md"; }
"#.replace('\n', "\r\n")),
("views.arcadia".into(), r#"diagram overview "Overview" id "10000000-0000-4000-8000-000000000008" { layer Oa; routes [{ edge @ // routed identity
transfer; waypoints [{ x 4.20e2; y -16; }]; }]; }
node placement id "10000000-0000-4000-8000-000000000009" { diagram @overview; element @assess; position { x -0.0; y 12.375; }; size { width 260; height 94; }; }
"#.replace('\n', "\r\n")),
]),
};
let document = Document::from_bundle(bundle.clone(), ProjectLimits::default()).unwrap();
assert_eq!(
document.bundle(),
&bundle,
"fixture must need no migration or ID insertion"
);
document
}
fn id(number: u8) -> Id {
Id::parse_str(&format!("10000000-0000-4000-8000-{number:012}")).unwrap()
}
fn prepare(document: &Document, target: Id, replacement: &str) -> PreparedAliasRename {
document
.alias_rename_request(target, replacement.into())
.unwrap()
.prepare()
.unwrap()
}
// Capture every live Document state relevant to refusal/no-op. Arc identity also
// catches replacing an equal snapshot or saved marker behind the user's back.
struct Unchanged {
current: Arc<CompiledSourceProject>,
saved: Option<Arc<SourceBundle>>,
past: Vec<(Arc<CompiledSourceProject>, usize)>,
future: Vec<(Arc<CompiledSourceProject>, usize)>,
revision: u64,
current_bytes: usize,
recovered: bool,
}
impl Unchanged {
fn capture(document: &Document) -> Self {
Self {
current: document.snapshot(),
saved: document.saved.clone(),
past: document
.past
.iter()
.map(|h| (h.snapshot.clone(), h.bytes))
.collect(),
future: document
.future
.iter()
.map(|h| (h.snapshot.clone(), h.bytes))
.collect(),
revision: document.revision,
current_bytes: document.current_bytes,
recovered: document.recovered_unsaved,
}
}
fn assert(&self, document: &Document) {
assert!(Arc::ptr_eq(&self.current, &document.current));
match (&self.saved, &document.saved) {
(Some(before), Some(after)) => assert!(Arc::ptr_eq(before, after)),
(None, None) => {}
_ => panic!("saved baseline changed"),
}
for (before, after) in [
(&self.past, &document.past),
(&self.future, &document.future),
] {
assert_eq!(before.len(), after.len());
for ((snapshot, bytes), entry) in before.iter().zip(after) {
assert!(Arc::ptr_eq(snapshot, &entry.snapshot));
assert_eq!(*bytes, entry.bytes);
}
}
assert_eq!(self.revision, document.revision);
assert_eq!(self.current_bytes, document.current_bytes);
assert_eq!(self.recovered, document.recovered_unsaved);
}
}
#[test]
fn each_identity_family_changes_only_authored_alias_roles_and_one_history_entry() {
// Literal role-specific replacements are independent of the updater/tokenizer.
// They deliberately exclude prose, historical review text and URI spelling.
type AliasCase<'a> = (u8, &'a str, &'a str, &'a [(&'a str, &'a str)]);
let cases: &[AliasCase<'_>] = &[
(
1,
"mission",
"renamed",
&[("project mission ", "project renamed ")],
),
(
2,
"assess",
"renamed",
&[
("oa_activity assess ", "oa_activity renamed "),
("\r\n assess;", "\r\n renamed;"),
("@assess;", "@renamed;"),
],
),
(
5,
"transfer",
"renamed",
&[
("interaction transfer ", "interaction renamed "),
("\r\n transfer;", "\r\n renamed;"),
],
),
(
6,
"review",
"renamed",
&[
("trace review ", "trace renamed "),
("owner @review;", "owner @renamed;"),
],
),
(
7,
"evidence",
"renamed",
&[("artifact evidence ", "artifact renamed ")],
),
(
8,
"overview",
"renamed",
&[
("diagram overview ", "diagram renamed "),
("diagram @overview;", "diagram @renamed;"),
],
),
(
9,
"placement",
"renamed",
&[("node placement ", "node renamed ")],
),
];
for &(number, old, new, replacements) in cases {
let mut document = fixture();
let original = document.snapshot();
let mut expected_model = document.project().clone();
// Explicit per-family oracle, separate from production expectation helper.
match number {
1 => expected_model.alias = new.into(),
2 => expected_model.elements.get_mut(&id(2)).unwrap().alias = new.into(),
5 => expected_model.relations.get_mut(&id(5)).unwrap().alias = new.into(),
6 => expected_model.traces.get_mut(&id(6)).unwrap().alias = new.into(),
7 => expected_model.artifact_links.get_mut(&id(7)).unwrap().alias = new.into(),
8 => expected_model.diagrams.get_mut(&id(8)).unwrap().alias = new.into(),
9 => {
expected_model
.diagrams
.get_mut(&id(8))
.unwrap()
.nodes
.get_mut(&id(9))
.unwrap()
.alias = new.into()
}
_ => unreachable!(),
}
let mut expected_bundle = document.bundle().clone();
for source in expected_bundle.files.values_mut() {
for &(before, after) in replacements {
*source = source.replace(before, after);
}
}
let state = Unchanged::capture(&document);
let prepared = prepare(&document, id(number), new);
state.assert(&document);
assert!(prepared.changed());
assert_eq!(prepared.old_alias(), old);
assert_eq!(prepared.new_alias(), new);
assert_eq!(prepared.target(), id(number));
assert_eq!(prepared.revision(), 0);
assert_eq!(prepared.before().bundle, original.bundle);
assert_eq!(prepared.after().bundle, expected_bundle);
assert_eq!(prepared.after().decoded.project, expected_model);
assert!(document.commit_alias_rename(&prepared).unwrap());
assert!(
Arc::ptr_eq(&document.current, &prepared.0.after),
"adopt the exact prepared Arc"
);
assert_eq!(document.past.len(), 1);
assert!(document.dirty());
let after = Unchanged::capture(&document);
assert!(document.commit_alias_rename(&prepared.clone()).is_err());
after.assert(&document);
assert!(document.undo());
assert!(Arc::ptr_eq(&document.current, &original));
assert!(!document.dirty());
assert!(!document.can_undo());
assert!(document.redo());
assert_eq!(document.bundle(), &expected_bundle);
assert_eq!(document.project(), &expected_model);
document.mark_saved(document.snapshot());
let reopened =
Document::from_bundle(document.bundle().clone(), ProjectLimits::default()).unwrap();
assert_eq!(reopened.project(), &expected_model);
assert_eq!(reopened.bundle(), &expected_bundle);
assert!(!reopened.dirty());
}
}
#[test]
fn highlighted_keyword_alias_is_valid_without_normalizing_input() {
assert!(matches!(
language::tokenize("oa_activity")[0].class,
language::TokenClass::Keyword
));
let mut document = fixture();
let prepared = prepare(&document, id(2), "oa_activity");
document.commit_alias_rename(&prepared).unwrap();
assert_eq!(document.project().elements[&id(2)].alias, "oa_activity");
assert_eq!(document.project().elements[&id(2)].name, "Оценка ущерба");
}
#[test]
fn invalid_and_identical_aliases_preserve_live_state_and_redo() {
let mut document = fixture();
let first = prepare(&document, id(2), "changed");
document.commit_alias_rename(&first).unwrap();
assert!(document.undo());
document.invalidate_saved_baseline();
document.mark_recovered();
let state = Unchanged::capture(&document);
for replacement in ["", "has space", "project", "assist", " assess", "assess "] {
assert!(
document
.alias_rename_request(id(2), replacement.into())
.unwrap()
.prepare()
.is_err()
);
state.assert(&document);
}
assert!(
document
.alias_rename_request(Id::nil(), "new".into())
.is_err()
);
let no_op = prepare(&document, id(2), "assess");
assert!(!no_op.changed());
assert!(!document.commit_alias_rename(&no_op).unwrap());
state.assert(&document);
assert!(document.redo());
assert_eq!(document.project().elements[&id(2)].alias, "changed");
}
#[test]
fn equal_bytes_undo_replay_cross_document_and_exhausted_revision_refuse() {
let mut document = fixture();
let old = prepare(&document, id(2), "renamed");
let mut second = fixture();
let second_state = Unchanged::capture(&second);
assert!(second.commit_alias_rename(&old).is_err());
second_state.assert(&second);
// Even an identical shared accepted Arc cannot confer this Document's owner.
second.current = document.current.clone();
let second_state = Unchanged::capture(&second);
assert!(second.commit_alias_rename(&old).is_err());
second_state.assert(&second);
document
.execute(Command::Rename(id(2), "Later name".into()))
.unwrap();
let edited = Unchanged::capture(&document);
assert!(document.commit_alias_rename(&old).is_err());
edited.assert(&document);
assert!(document.undo());
assert!(Arc::ptr_eq(&document.current, &old.0.request.before));
let undone = Unchanged::capture(&document);
assert!(document.commit_alias_rename(&old).is_err());
undone.assert(&document);
document.revision = u64::MAX - 1;
let last = prepare(&document, id(2), "renamed");
document
.execute(Command::Rename(id(2), "Exhaust revision".into()))
.unwrap();
document.undo();
assert!(Arc::ptr_eq(&document.current, &last.0.request.before));
let exhausted = Unchanged::capture(&document);
assert!(document.commit_alias_rename(&last).is_err());
assert!(
document
.alias_rename_request(id(2), "renamed".into())
.is_err()
);
assert!(
document
.alias_rename_request(id(2), "assess".into())
.is_err()
);
exhausted.assert(&document);
}
#[test]
fn preview_retains_latest_saved_baseline_and_recovery_state() {
for baseline in ["saved_before", "unknown", "raw_repair", "recovered"] {
let mut document = fixture();
let prepared = prepare(&document, id(2), "renamed");
let original = document.snapshot();
match baseline {
"saved_before" => document.mark_saved(original.clone()),
"unknown" => document.invalidate_saved_baseline(),
"raw_repair" => {
let mut raw = document.bundle().clone();
raw.files
.insert("project.arcadia".into(), "invalid repair source".into());
document.bind_repair_baseline(raw);
}
"recovered" => document.mark_recovered(),
_ => unreachable!(),
}
let saved = document.saved.clone();
let recovered = document.recovered_unsaved;
assert!(document.commit_alias_rename(&prepared).unwrap());
assert_eq!(document.saved, saved);
assert_eq!(document.recovered_unsaved, recovered);
assert!(document.dirty());
assert!(document.undo());
assert_eq!(document.saved, saved);
assert_eq!(document.recovered_unsaved, recovered);
assert_eq!(document.dirty(), baseline != "saved_before");
}
// A completed save after Preview remains authoritative, including when it
// clears recovery; a worker must not restore its earlier state on Confirm.
let mut document = fixture();
document.mark_recovered();
document.invalidate_saved_baseline();
let prepared = prepare(&document, id(2), "renamed");
document.mark_saved(document.snapshot());
document.commit_alias_rename(&prepared).unwrap();
assert!(!document.recovered_unsaved);
document.undo();
assert!(!document.dirty());
// Undo from saved C to B, then a new B->C rename can correctly finish clean.
document.redo();
document.mark_saved(document.snapshot());
document.undo();
let return_to_saved = prepare(&document, id(2), "renamed");
document.commit_alias_rename(&return_to_saved).unwrap();
assert!(!document.dirty());
assert!(!document.can_redo());
}
#[test]
fn mutable_public_preview_copies_cannot_change_prepared_authority() {
let mut document = fixture();
let prepared = prepare(&document, id(2), "renamed");
let exact = prepared.after().clone();
let mut counterfeit = prepared.after().clone();
counterfeit.decoded.project.name = "Injected unrelated edit".into();
counterfeit.index.declarations.clear();
let unchanged = Unchanged::capture(&document);
assert!(document.apply_compiled(counterfeit).is_err());
unchanged.assert(&document);
let mut unrelated = exact.decoded.project.clone();
unrelated.name = "A self-consistent unrelated candidate".into();
let forged_dto = source_project::compile_bundle(
&source_project::format_bundle(&unrelated),
ProjectLimits::default(),
)
.unwrap();
assert_ne!(forged_dto.decoded.project, prepared.after().decoded.project);
// No API converts either DTO to PreparedAliasRename. Mutating owned copies
// leaves the opaque capability and its exact adopted model/source intact.
document.commit_alias_rename(&prepared).unwrap();
assert_eq!(document.project(), &exact.decoded.project);
assert_eq!(document.bundle(), &exact.bundle);
}
#[test]
fn exact_history_capacity_admits_immediate_undo_and_rejects_larger_candidate() {
let mut document = fixture();
let mut bundle = document.bundle().clone();
let padding = HISTORY_BYTES / 2 - document.current_bytes;
bundle
.files
.get_mut("views.arcadia")
.unwrap()
.push_str(&format!("//{}\r\n", "x".repeat(padding - 4)));
document.apply_bundle(bundle).unwrap();
assert_eq!(document.current_bytes, HISTORY_BYTES / 2);
// A same-length alias retains the exact estimate; older history is evictable.
let boundary = prepare(&document, id(2), "rating");
assert_eq!(
boundary.0.before_bytes + boundary.0.after_bytes,
HISTORY_BYTES
);
let unchanged = Unchanged::capture(&document);
assert!(
document
.alias_rename_request(id(2), "longer_alias".into())
.unwrap()
.prepare()
.is_err()
);
unchanged.assert(&document);
document.commit_alias_rename(&boundary).unwrap();
assert_eq!(document.past.len(), 1);
assert!(document.undo());
assert!(Arc::ptr_eq(&document.current, &boundary.0.request.before));
assert!(!document.can_undo());
assert!(document.redo());
assert!(Arc::ptr_eq(&document.current, &boundary.0.after));
assert!(check_history_capacity(usize::MAX, 1).is_err());
assert!(check_history_capacity(HISTORY_BYTES, 1).is_err());
}
#[test]
fn mint_and_commit_refuse_exhausted_or_inconsistent_live_history_estimate() {
let mut document = fixture();
let prepared = prepare(&document, id(2), "renamed");
// Inject cache corruption to falsify the commit-side check independently of
// the preparation admission. Normal edits also change revision and Arc.
document.current_bytes = HISTORY_BYTES;
let unchanged = Unchanged::capture(&document);
assert!(
document
.alias_rename_request(id(2), "renamed".into())
.is_err()
);
assert!(document.commit_alias_rename(&prepared).is_err());
// No-op intent needs no Undo reservation even at the admission boundary.
assert!(
document
.alias_rename_request(id(2), "assess".into())
.is_ok()
);
unchanged.assert(&document);
}
File diff suppressed because it is too large Load Diff
+1
View File
@@ -24,6 +24,7 @@ mod recovery;
mod route_edit;
mod semantic_review;
mod source_navigation;
mod source_rename;
mod source_tree;
mod source_workspace;
mod style;
@@ -1,147 +1,147 @@
use super::artifacts::{Editor, Event, Raw};
use super::*;
use iced::{
Element as View, Fill,
widget::{button, checkbox, column, pick_list, row, text, text_editor, text_input},
};
pub(super) fn pairs<'a>(editor: &'a Editor, p: &'a Project, trace: &'a Trace) -> View<'a, Event> {
let mut content=column![text("Artifact links and metadata").size(16),text("Pair links attached to these reviewed owners. Presence is attachment to the owner; taking identified source absence deletes the destination link, while a destination-only link is retained.").size(12),text_input("Filter artifact identities",&editor.search).on_input(Event::Search).padding(7)].spacing(9);
for (layer, label, selected) in [
(Layer::Oa, "Operational", editor.oa.clone()),
(Layer::Sa, "System", editor.sa.clone()),
] {
content = content.push(text(label).size(12)).push(
row![
pick_list(editor.choices(p, trace, layer), selected, move |v| {
Event::Pick(layer, Some(v))
})
.placeholder("Choose exact artifact identity")
.width(Fill)
.padding(7),
button("No identity")
.padding(7)
.on_press(Event::Pick(layer, None))
]
.spacing(7),
);
}
content.push(row![button("Reserve a new destination counterpart").padding(7).on_press(Event::Reserve),button("Review this exact artifact pair").padding(7).on_press(Event::Stage)].spacing(7).wrap()).push(text("Reservation retains a fresh identity and seeds metadata from the source. It creates nothing until Presence and all seven metadata facets are explicitly reviewed and the combined Apply succeeds. New unrelated links use ordinary artifact creation.").size(11)).padding(iced::Padding::default().right(18)).into()
}
pub(super) fn candidate<'a>(
editor: &'a Editor,
p: &'a Project,
facet: &'a FacetSelector,
) -> Option<View<'a, Event>> {
let value = editor.drafts.get(facet)?;
let (_, which) = artifacts::parts(facet)?;
let mut content =
column![text(format!("Final artifact {}", artifacts::field(which)?)).size(12)].spacing(7);
match value {
Raw::Text(_) if which == ArtifactFacet::Description => {
let draft = editor.descriptions.get(facet)?;
let facet = facet.clone();
content = content.push(
text_editor(draft)
.height(110)
.on_action(move |action| Event::Description(facet.clone(), action)),
);
}
Raw::Text(value) => {
let facet = facet.clone();
content = content.push(
text_input("Exact text", value)
.on_input(move |value| Event::Input(facet.clone(), Raw::Text(value)))
.padding(7),
);
}
Raw::Owner(value) => {
let mut choices: Vec<_> = p
.identities()
.into_iter()
.map(|(id, alias)| Choice {
id,
label: format!("{} · @{alias}", p.named(id)),
})
.collect();
choices.sort_by_cached_key(|c| c.label.to_lowercase());
let selected = value.parse::<Id>().ok().map(|id| view::choice(p, id));
let raw_facet = facet.clone();
let pick_facet = facet.clone();
content = content
.push(
pick_list(choices, selected, move |v: Choice| {
Event::Input(pick_facet.clone(), Raw::Owner(v.id.to_string()))
})
.placeholder("Explicit final owner")
.width(Fill)
.padding(7),
)
.push(
text_input("Owner identity (retains rejected input)", value)
.on_input(move |v| Event::Input(raw_facet.clone(), Raw::Owner(v)))
.padding(7),
);
}
Raw::Relation(value) => {
let facet = facet.clone();
let variants = [
ArtifactRelation::References,
ArtifactRelation::Satisfies,
ArtifactRelation::Verifies,
ArtifactRelation::Implements,
ArtifactRelation::DerivedFrom,
];
let choices: Vec<_> = variants.into_iter().map(RelationChoice).collect();
content = content.push(
pick_list(choices, Some(RelationChoice(*value)), move |v| {
Event::Input(facet.clone(), Raw::Relation(v.0))
})
.padding(7),
);
}
Raw::Optional {
present,
text: value,
} => {
let toggle_facet = facet.clone();
let retained = value.clone();
let input_facet = facet.clone();
let enabled = *present;
content = content
.push(
checkbox(*present)
.label("Present (checked with empty text means an explicit empty value)")
.on_toggle(move |present| {
Event::Input(
toggle_facet.clone(),
Raw::Optional {
present,
text: retained.clone(),
},
)
}),
)
.push(
text_input("Retained optional text", value)
.on_input(move |text| {
Event::Input(
input_facet.clone(),
Raw::Optional {
present: enabled,
text,
},
)
})
.padding(7),
);
}
}
Some(content.into())
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct RelationChoice(ArtifactRelation);
impl std::fmt::Display for RelationChoice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
use super::artifacts::{Editor, Event, Raw};
use super::*;
use iced::{
Element as View, Fill,
widget::{button, checkbox, column, pick_list, row, text, text_editor, text_input},
};
pub(super) fn pairs<'a>(editor: &'a Editor, p: &'a Project, trace: &'a Trace) -> View<'a, Event> {
let mut content=column![text("Artifact links and metadata").size(16),text("Pair links attached to these reviewed owners. Presence is attachment to the owner; taking identified source absence deletes the destination link, while a destination-only link is retained.").size(12),text_input("Filter artifact identities",&editor.search).on_input(Event::Search).padding(7)].spacing(9);
for (layer, label, selected) in [
(Layer::Oa, "Operational", editor.oa.clone()),
(Layer::Sa, "System", editor.sa.clone()),
] {
content = content.push(text(label).size(12)).push(
row![
pick_list(editor.choices(p, trace, layer), selected, move |v| {
Event::Pick(layer, Some(v))
})
.placeholder("Choose exact artifact identity")
.width(Fill)
.padding(7),
button("No identity")
.padding(7)
.on_press(Event::Pick(layer, None))
]
.spacing(7),
);
}
content.push(row![button("Reserve a new destination counterpart").padding(7).on_press(Event::Reserve),button("Review this exact artifact pair").padding(7).on_press(Event::Stage)].spacing(7).wrap()).push(text("Reservation retains a fresh identity and seeds metadata from the source. It creates nothing until Presence and all seven metadata facets are explicitly reviewed and the combined Apply succeeds. New unrelated links use ordinary artifact creation.").size(11)).padding(iced::Padding::default().right(18)).into()
}
pub(super) fn candidate<'a>(
editor: &'a Editor,
p: &'a Project,
facet: &'a FacetSelector,
) -> Option<View<'a, Event>> {
let value = editor.drafts.get(facet)?;
let (_, which) = artifacts::parts(facet)?;
let mut content =
column![text(format!("Final artifact {}", artifacts::field(which)?)).size(12)].spacing(7);
match value {
Raw::Text(_) if which == ArtifactFacet::Description => {
let draft = editor.descriptions.get(facet)?;
let facet = facet.clone();
content = content.push(
text_editor(draft)
.height(110)
.on_action(move |action| Event::Description(facet.clone(), action)),
);
}
Raw::Text(value) => {
let facet = facet.clone();
content = content.push(
text_input("Exact text", value)
.on_input(move |value| Event::Input(facet.clone(), Raw::Text(value)))
.padding(7),
);
}
Raw::Owner(value) => {
let mut choices: Vec<_> = p
.identities()
.into_iter()
.map(|(id, alias)| Choice {
id,
label: format!("{} · @{alias}", p.named(id)),
})
.collect();
choices.sort_by_cached_key(|c| c.label.to_lowercase());
let selected = value.parse::<Id>().ok().map(|id| view::choice(p, id));
let raw_facet = facet.clone();
let pick_facet = facet.clone();
content = content
.push(
pick_list(choices, selected, move |v: Choice| {
Event::Input(pick_facet.clone(), Raw::Owner(v.id.to_string()))
})
.placeholder("Explicit final owner")
.width(Fill)
.padding(7),
)
.push(
text_input("Owner identity (retains rejected input)", value)
.on_input(move |v| Event::Input(raw_facet.clone(), Raw::Owner(v)))
.padding(7),
);
}
Raw::Relation(value) => {
let facet = facet.clone();
let variants = [
ArtifactRelation::References,
ArtifactRelation::Satisfies,
ArtifactRelation::Verifies,
ArtifactRelation::Implements,
ArtifactRelation::DerivedFrom,
];
let choices: Vec<_> = variants.into_iter().map(RelationChoice).collect();
content = content.push(
pick_list(choices, Some(RelationChoice(*value)), move |v| {
Event::Input(facet.clone(), Raw::Relation(v.0))
})
.padding(7),
);
}
Raw::Optional {
present,
text: value,
} => {
let toggle_facet = facet.clone();
let retained = value.clone();
let input_facet = facet.clone();
let enabled = *present;
content = content
.push(
checkbox(*present)
.label("Present (checked with empty text means an explicit empty value)")
.on_toggle(move |present| {
Event::Input(
toggle_facet.clone(),
Raw::Optional {
present,
text: retained.clone(),
},
)
}),
)
.push(
text_input("Retained optional text", value)
.on_input(move |text| {
Event::Input(
input_facet.clone(),
Raw::Optional {
present: enabled,
text,
},
)
})
.padding(7),
);
}
}
Some(content.into())
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct RelationChoice(ArtifactRelation);
impl std::fmt::Display for RelationChoice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
@@ -1,79 +1,79 @@
//! Explicit attachment pair and final destination field controls.
use super::{
attachments::{Editor, Event, Family},
*,
};
use iced::{
Element as View, Fill,
widget::{button, column, pick_list, row, text, text_input},
};
pub(super) fn pairs<'a>(
editor: &'a Editor,
project: &'a Project,
trace: &'a Trace,
) -> View<'a, Event> {
let mut content = column![
text("Existing children and relationship endpoints").size(16),
text("Choose explicit Operational and System identities. A child's final parent or a relationship's final endpoint is reviewed independently; opening another trace keeps this draft.").size(12),
pick_list([Family::Child, Family::Source, Family::Target], Some(editor.family), Event::Family).text_size(12).padding(7).width(Fill),
text_input("Filter attachment identities by name or alias", &editor.search).on_input(Event::Search).size(12).padding(7),
].spacing(9);
for layer in [Layer::Oa, Layer::Sa] {
let label = if layer == Layer::Oa {
"Operational"
} else {
"System"
};
let owner = if layer == Layer::Oa {
trace.oa
} else {
trace.sa
};
content = content.push(text(format!("{label} owner: {}", project.named(owner))).size(12));
content = content.push(
row![
pick_list(
editor.choices(project, trace, layer),
editor.selection(layer).cloned(),
move |choice| Event::Pick(layer, Some(choice))
)
.placeholder(format!("Choose an existing {label} identity"))
.text_size(12)
.padding(7)
.width(Fill),
button(text("No identity on this side").size(11))
.style(crate::style::nav)
.padding(7)
.on_press(Event::Pick(layer, None)),
]
.spacing(7),
);
}
content = content.push(
button(text("Use exact attachment pair").size(12))
.padding(8)
.style(crate::style::nav)
.on_press(Event::Stage),
);
content.push(text("Taking an absent relationship endpoint requires an explicit final replacement. New child and relationship creation uses a separate explicit transition mapping.").size(11)).padding(iced::Padding::default().right(18)).into()
}
pub(super) fn candidate<'a>(
editor: &'a Editor,
project: &'a Project,
facet: &'a FacetSelector,
layer: Layer,
) -> Option<View<'a, Message>> {
let draft = editor.drafts.get(facet)?;
let (id, _) = attachments::actual_slot(facet, layer)?;
let path = attachments::path(project, facet, layer)?;
Some(
column![
text(format!("Destination record: {}", project.named(id))).size(12),
crate::forms::scoped(draft, project, &path, attachments::label(facet)),
]
.spacing(7)
.into(),
)
}
//! Explicit attachment pair and final destination field controls.
use super::{
attachments::{Editor, Event, Family},
*,
};
use iced::{
Element as View, Fill,
widget::{button, column, pick_list, row, text, text_input},
};
pub(super) fn pairs<'a>(
editor: &'a Editor,
project: &'a Project,
trace: &'a Trace,
) -> View<'a, Event> {
let mut content = column![
text("Existing children and relationship endpoints").size(16),
text("Choose explicit Operational and System identities. A child's final parent or a relationship's final endpoint is reviewed independently; opening another trace keeps this draft.").size(12),
pick_list([Family::Child, Family::Source, Family::Target], Some(editor.family), Event::Family).text_size(12).padding(7).width(Fill),
text_input("Filter attachment identities by name or alias", &editor.search).on_input(Event::Search).size(12).padding(7),
].spacing(9);
for layer in [Layer::Oa, Layer::Sa] {
let label = if layer == Layer::Oa {
"Operational"
} else {
"System"
};
let owner = if layer == Layer::Oa {
trace.oa
} else {
trace.sa
};
content = content.push(text(format!("{label} owner: {}", project.named(owner))).size(12));
content = content.push(
row![
pick_list(
editor.choices(project, trace, layer),
editor.selection(layer).cloned(),
move |choice| Event::Pick(layer, Some(choice))
)
.placeholder(format!("Choose an existing {label} identity"))
.text_size(12)
.padding(7)
.width(Fill),
button(text("No identity on this side").size(11))
.style(crate::style::nav)
.padding(7)
.on_press(Event::Pick(layer, None)),
]
.spacing(7),
);
}
content = content.push(
button(text("Use exact attachment pair").size(12))
.padding(8)
.style(crate::style::nav)
.on_press(Event::Stage),
);
content.push(text("Taking an absent relationship endpoint requires an explicit final replacement. New child and relationship creation uses a separate explicit transition mapping.").size(11)).padding(iced::Padding::default().right(18)).into()
}
pub(super) fn candidate<'a>(
editor: &'a Editor,
project: &'a Project,
facet: &'a FacetSelector,
layer: Layer,
) -> Option<View<'a, Message>> {
let draft = editor.drafts.get(facet)?;
let (id, _) = attachments::actual_slot(facet, layer)?;
let path = attachments::path(project, facet, layer)?;
Some(
column![
text(format!("Destination record: {}", project.named(id))).size(12),
crate::forms::scoped(draft, project, &path, attachments::label(facet)),
]
.spacing(7)
.into(),
)
}
+350 -350
View File
@@ -1,350 +1,350 @@
//! Closed presence-only adapter. The core independently validates the full final record.
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Family {
Member(ReferenceCollection),
Literal,
Annotation,
Binding,
}
impl std::fmt::Display for Family {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Member(ReferenceCollection::FunctionInputItems) => "Function input items",
Self::Member(ReferenceCollection::FunctionOutputItems) => "Function output items",
Self::Member(ReferenceCollection::SignalItems) => "Signal items",
Self::Member(ReferenceCollection::CategoryExchanges) => "Category exchanges",
Self::Member(ReferenceCollection::ExchangeItems) => "Exchange items",
Self::Member(ReferenceCollection::TransitionTriggers) => "Transition triggers",
Self::Member(ReferenceCollection::TransitionEffects) => "Transition effects",
Self::Member(ReferenceCollection::Constrained) => "Constrained identities",
Self::Member(ReferenceCollection::Steps) => "Ordered steps",
Self::Member(ReferenceCollection::FragmentBranches) => "Fragment branches",
Self::Literal => "Enumeration literals",
Self::Annotation => "Message values",
Self::Binding => "Scenario lifeline bindings",
})
}
}
pub(super) const FAMILIES: [Family; 13] = [
Family::Member(ReferenceCollection::Steps),
Family::Member(ReferenceCollection::FragmentBranches),
Family::Member(ReferenceCollection::FunctionInputItems),
Family::Member(ReferenceCollection::FunctionOutputItems),
Family::Member(ReferenceCollection::SignalItems),
Family::Member(ReferenceCollection::ExchangeItems),
Family::Member(ReferenceCollection::CategoryExchanges),
Family::Member(ReferenceCollection::TransitionTriggers),
Family::Member(ReferenceCollection::TransitionEffects),
Family::Member(ReferenceCollection::Constrained),
Family::Literal,
Family::Annotation,
Family::Binding,
];
pub(super) fn family(facet: &FacetSelector) -> Option<Family> {
let family = match facet {
FacetSelector::Member { collection, .. } => Family::Member(*collection),
FacetSelector::Literal(_) => Family::Literal,
FacetSelector::Annotation(_) => Family::Annotation,
FacetSelector::Binding(_) => Family::Binding,
_ => return None,
};
FAMILIES.contains(&family).then_some(family)
}
pub(super) fn supported(facet: &FacetSelector) -> bool {
family(facet).is_some()
}
// Fixed paths for the closed collections and the exact enum literal set.
// They are selected by the typed facet; callers cannot supply arbitrary paths.
pub(super) fn path(value: &Value, family: Family) -> Option<String> {
let prefixes = ["/body/Oa/Shared", "/body/Sa/Shared"];
let tails: &[&str] = match family {
Family::Member(ReferenceCollection::Steps) => {
return [
"/body/Oa/Process/steps",
"/body/Sa/FunctionalChain/steps",
"/body/Oa/Shared/Scenario/steps",
"/body/Sa/Shared/Scenario/steps",
"/body/Oa/Shared/Occurrence/body/Branch/occurrences",
"/body/Sa/Shared/Occurrence/body/Branch/occurrences",
]
.into_iter()
.find(|p| value.pointer(p).is_some_and(Value::is_array))
.map(str::to_owned);
}
Family::Member(ReferenceCollection::FragmentBranches) => {
&["Occurrence/body/Fragment/branches"]
}
Family::Member(ReferenceCollection::FunctionInputItems) => {
&["Port/contract/FunctionInput/incoming_items"]
}
Family::Member(ReferenceCollection::FunctionOutputItems) => {
&["Port/contract/FunctionOutput/outgoing_items"]
}
Family::Member(ReferenceCollection::CategoryExchanges) => &["ExchangeCategory/exchanges"],
Family::Member(ReferenceCollection::SignalItems) => &["Event/body/Signal/items"],
Family::Member(ReferenceCollection::Constrained) => &["Constraint/constrained"],
Family::Literal => &["DataType/definition/Enumeration/literals"],
Family::Annotation => &["Occurrence/body/Exchange/values"],
Family::Binding => &["Occurrence/body/ScenarioUse/bindings"],
Family::Member(ReferenceCollection::ExchangeItems) => {
return [
"Interaction",
"FunctionalExchange",
"BoundaryExchange",
"CommunicationMean",
]
.iter()
.map(|kind| format!("/body/{kind}/items"))
.find(|p| value.pointer(p).is_some_and(Value::is_array));
}
Family::Member(ReferenceCollection::TransitionTriggers) => {
return value
.pointer("/body/StateTransition/triggers")
.is_some_and(Value::is_array)
.then(|| "/body/StateTransition/triggers".into());
}
Family::Member(ReferenceCollection::TransitionEffects) => {
return value
.pointer("/body/StateTransition/effects")
.is_some_and(Value::is_array)
.then(|| "/body/StateTransition/effects".into());
}
};
prefixes
.iter()
.flat_map(|prefix| tails.iter().map(move |tail| format!("{prefix}/{tail}")))
.find(|p| value.pointer(p).is_some_and(Value::is_array))
}
pub(super) fn key(facet: &FacetSelector, layer: Layer) -> Option<Value> {
match facet {
FacetSelector::Member { keys, .. } => if layer == Layer::Oa { keys.oa } else { keys.sa }
.map(|id| serde_json::to_value(id).expect("Id")),
FacetSelector::Literal(keys) => if layer == Layer::Oa {
keys.oa.as_ref()
} else {
keys.sa.as_ref()
}
.map(|v| Value::String(v.clone())),
FacetSelector::Annotation(keys) => if layer == Layer::Oa {
keys.oa.as_ref()
} else {
keys.sa.as_ref()
}
.map(|key| serde_json::to_value(key).expect("Annotation key")),
FacetSelector::Binding(keys) => if layer == Layer::Oa { keys.oa } else { keys.sa }
.map(|id| serde_json::to_value(id).expect("Binding key")),
_ => None,
}
}
pub(super) fn overlap(a: &FacetSelector, b: &FacetSelector) -> bool {
if family(a).is_none() || family(a) != family(b) {
return false;
}
[Layer::Oa, Layer::Sa]
.into_iter()
.any(|layer| key(a, layer).is_some() && key(a, layer) == key(b, layer))
}
pub(super) fn project_presence(
value: &mut Value,
facet: &FacetSelector,
layer: Layer,
present: bool,
) -> Result<(), String> {
let family = family(facet).ok_or("This keyed family remains read-only.")?;
let key = key(facet, layer)
.ok_or("Choose the destination identity in Members before setting or taking presence.")?;
let path =
path(value, family).ok_or("This collection is not applicable to the destination kind.")?;
let list = value
.pointer_mut(&path)
.and_then(Value::as_array_mut)
.ok_or("Destination collection is unavailable.")?;
if present {
if !list.contains(&key) {
list.push(key);
}
} else {
list.retain(|v| v != &key);
}
Ok(())
}
impl ReviewRow {
pub(super) fn keyed_value(
&self,
project: &Project,
trace: &Trace,
value: &mut Value,
facet: &FacetSelector,
decision: SemanticDecision,
) -> Result<(), String> {
if keyed_rows::supported(facet) {
return self.project_row(project, trace, value, facet, decision);
}
let present = match decision {
SemanticDecision::KeepTarget => return Ok(()),
SemanticDecision::TakeSource => {
// A missing source identity is a target-local row, not a removal.
if key(facet, self.direction.source_layer()).is_none() {
return Ok(());
}
let fact = capture_facet(project, trace.oa, trace.sa, facet)?;
scalar::value(&fact, self.direction.source_layer()).and_then(|v| v.as_bool()).ok_or("Source collection is not applicable; choose an explicit final presence or Keep.")?
}
SemanticDecision::Candidate => *self
.presence
.get(facet)
.ok_or("Choose final membership presence.")?,
};
project_presence(value, facet, self.direction.target_layer(), present)
}
pub(super) fn member_families(&self, project: &Project) -> Vec<Family> {
let Some(trace) = self.effective_trace(project) else {
return vec![];
};
let values: Vec<_> = [trace.oa, trace.sa]
.into_iter()
.filter_map(|id| Draft::from_project(project, id).map(|d| d.value))
.collect();
FAMILIES
.into_iter()
.filter(|family| values.iter().any(|value| path(value, *family).is_some()))
.collect()
}
pub(super) fn member_choices(&self, project: &Project, layer: Layer) -> Vec<Choice> {
if self.member_family == Family::Binding {
return self.binding_choices(project, layer, true);
}
let Some(trace) = self.effective_trace(project) else {
return vec![];
};
let id = if layer == Layer::Oa {
trace.oa
} else {
trace.sa
};
let Some(mut draft) = Draft::from_project(project, id) else {
return vec![];
};
if layer == self.direction.target_layer() {
draft.set_context(self.combined_value(project, true).ok());
}
let selected = if layer == Layer::Oa {
&self.member_oa
} else {
&self.member_sa
};
let Some(path) = path(&draft.context_value(), self.member_family) else {
return selected.iter().cloned().collect();
};
crate::forms::reference_choices(
&draft,
project,
&format!("{path}/0"),
selected.as_ref().map_or(Id::nil(), |c| c.id),
)
.into_iter()
.filter(|c| !c.id.is_nil())
.collect()
}
pub(super) fn edit_pair(
&mut self,
project: &Project,
facet: FacetSelector,
) -> Result<(), String> {
self.member_family = family(&facet).ok_or("This keyed family remains read-only.")?;
match facet {
FacetSelector::Annotation(keys) => {
self.annotation_oa.selected = keys.oa.map(|key| crate::data_values::FieldPathKey {
path: key.path,
field: key.field,
});
self.annotation_sa.selected = keys.sa.map(|key| crate::data_values::FieldPathKey {
path: key.path,
field: key.field,
});
}
FacetSelector::Binding(keys) => {
self.member_oa = keys.oa.map(|id| view::choice(project, id));
self.member_sa = keys.sa.map(|id| view::choice(project, id));
}
FacetSelector::Member { keys, .. } => {
self.member_oa = keys.oa.map(|id| view::choice(project, id));
self.member_sa = keys.sa.map(|id| view::choice(project, id));
}
FacetSelector::Literal(keys) => {
self.literal_oa = keys.oa.is_some();
self.literal_sa = keys.sa.is_some();
self.literal = keys.oa.or(keys.sa).unwrap_or_default();
}
_ => unreachable!(),
}
self.tab = Tab::Members;
Ok(())
}
pub(super) fn stage_member(&mut self, project: &Project) -> Result<(), String> {
if !FAMILIES.contains(&self.member_family) {
return Err("This keyed family remains read-only.".into());
}
let facet = match self.member_family {
Family::Member(collection) => FacetSelector::Member {
collection,
keys: KeyPair {
oa: self.member_oa.as_ref().map(|c| c.id),
sa: self.member_sa.as_ref().map(|c| c.id),
},
},
Family::Literal => FacetSelector::Literal(KeyPair {
oa: self.literal_oa.then(|| self.literal.clone()),
sa: self.literal_sa.then(|| self.literal.clone()),
}),
Family::Annotation => FacetSelector::Annotation(KeyPair {
oa: self
.annotation_oa
.selected
.as_ref()
.map(|key| AnnotationKey {
path: key.path.clone(),
field: key.field,
}),
sa: self
.annotation_sa
.selected
.as_ref()
.map(|key| AnnotationKey {
path: key.path.clone(),
field: key.field,
}),
}),
Family::Binding => FacetSelector::Binding(KeyPair {
oa: self.member_oa.as_ref().map(|c| c.id),
sa: self.member_sa.as_ref().map(|c| c.id),
}),
};
let trace = self.effective_trace(project).ok_or("Choose a trace.")?;
capture_facet(project, trace.oa, trace.sa, &facet)?;
self.stage_row_references(&facet)?;
if let FacetSelector::Member {
keys:
KeyPair {
oa: Some(oa),
sa: Some(sa),
},
..
} = &facet
{
self.references.insert(*oa, *sa);
}
self.staged.insert(facet.clone());
self.selected = Some(facet);
self.tab = Tab::Facts;
Ok(())
}
}
//! Closed presence-only adapter. The core independently validates the full final record.
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Family {
Member(ReferenceCollection),
Literal,
Annotation,
Binding,
}
impl std::fmt::Display for Family {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Member(ReferenceCollection::FunctionInputItems) => "Function input items",
Self::Member(ReferenceCollection::FunctionOutputItems) => "Function output items",
Self::Member(ReferenceCollection::SignalItems) => "Signal items",
Self::Member(ReferenceCollection::CategoryExchanges) => "Category exchanges",
Self::Member(ReferenceCollection::ExchangeItems) => "Exchange items",
Self::Member(ReferenceCollection::TransitionTriggers) => "Transition triggers",
Self::Member(ReferenceCollection::TransitionEffects) => "Transition effects",
Self::Member(ReferenceCollection::Constrained) => "Constrained identities",
Self::Member(ReferenceCollection::Steps) => "Ordered steps",
Self::Member(ReferenceCollection::FragmentBranches) => "Fragment branches",
Self::Literal => "Enumeration literals",
Self::Annotation => "Message values",
Self::Binding => "Scenario lifeline bindings",
})
}
}
pub(super) const FAMILIES: [Family; 13] = [
Family::Member(ReferenceCollection::Steps),
Family::Member(ReferenceCollection::FragmentBranches),
Family::Member(ReferenceCollection::FunctionInputItems),
Family::Member(ReferenceCollection::FunctionOutputItems),
Family::Member(ReferenceCollection::SignalItems),
Family::Member(ReferenceCollection::ExchangeItems),
Family::Member(ReferenceCollection::CategoryExchanges),
Family::Member(ReferenceCollection::TransitionTriggers),
Family::Member(ReferenceCollection::TransitionEffects),
Family::Member(ReferenceCollection::Constrained),
Family::Literal,
Family::Annotation,
Family::Binding,
];
pub(super) fn family(facet: &FacetSelector) -> Option<Family> {
let family = match facet {
FacetSelector::Member { collection, .. } => Family::Member(*collection),
FacetSelector::Literal(_) => Family::Literal,
FacetSelector::Annotation(_) => Family::Annotation,
FacetSelector::Binding(_) => Family::Binding,
_ => return None,
};
FAMILIES.contains(&family).then_some(family)
}
pub(super) fn supported(facet: &FacetSelector) -> bool {
family(facet).is_some()
}
// Fixed paths for the closed collections and the exact enum literal set.
// They are selected by the typed facet; callers cannot supply arbitrary paths.
pub(super) fn path(value: &Value, family: Family) -> Option<String> {
let prefixes = ["/body/Oa/Shared", "/body/Sa/Shared"];
let tails: &[&str] = match family {
Family::Member(ReferenceCollection::Steps) => {
return [
"/body/Oa/Process/steps",
"/body/Sa/FunctionalChain/steps",
"/body/Oa/Shared/Scenario/steps",
"/body/Sa/Shared/Scenario/steps",
"/body/Oa/Shared/Occurrence/body/Branch/occurrences",
"/body/Sa/Shared/Occurrence/body/Branch/occurrences",
]
.into_iter()
.find(|p| value.pointer(p).is_some_and(Value::is_array))
.map(str::to_owned);
}
Family::Member(ReferenceCollection::FragmentBranches) => {
&["Occurrence/body/Fragment/branches"]
}
Family::Member(ReferenceCollection::FunctionInputItems) => {
&["Port/contract/FunctionInput/incoming_items"]
}
Family::Member(ReferenceCollection::FunctionOutputItems) => {
&["Port/contract/FunctionOutput/outgoing_items"]
}
Family::Member(ReferenceCollection::CategoryExchanges) => &["ExchangeCategory/exchanges"],
Family::Member(ReferenceCollection::SignalItems) => &["Event/body/Signal/items"],
Family::Member(ReferenceCollection::Constrained) => &["Constraint/constrained"],
Family::Literal => &["DataType/definition/Enumeration/literals"],
Family::Annotation => &["Occurrence/body/Exchange/values"],
Family::Binding => &["Occurrence/body/ScenarioUse/bindings"],
Family::Member(ReferenceCollection::ExchangeItems) => {
return [
"Interaction",
"FunctionalExchange",
"BoundaryExchange",
"CommunicationMean",
]
.iter()
.map(|kind| format!("/body/{kind}/items"))
.find(|p| value.pointer(p).is_some_and(Value::is_array));
}
Family::Member(ReferenceCollection::TransitionTriggers) => {
return value
.pointer("/body/StateTransition/triggers")
.is_some_and(Value::is_array)
.then(|| "/body/StateTransition/triggers".into());
}
Family::Member(ReferenceCollection::TransitionEffects) => {
return value
.pointer("/body/StateTransition/effects")
.is_some_and(Value::is_array)
.then(|| "/body/StateTransition/effects".into());
}
};
prefixes
.iter()
.flat_map(|prefix| tails.iter().map(move |tail| format!("{prefix}/{tail}")))
.find(|p| value.pointer(p).is_some_and(Value::is_array))
}
pub(super) fn key(facet: &FacetSelector, layer: Layer) -> Option<Value> {
match facet {
FacetSelector::Member { keys, .. } => if layer == Layer::Oa { keys.oa } else { keys.sa }
.map(|id| serde_json::to_value(id).expect("Id")),
FacetSelector::Literal(keys) => if layer == Layer::Oa {
keys.oa.as_ref()
} else {
keys.sa.as_ref()
}
.map(|v| Value::String(v.clone())),
FacetSelector::Annotation(keys) => if layer == Layer::Oa {
keys.oa.as_ref()
} else {
keys.sa.as_ref()
}
.map(|key| serde_json::to_value(key).expect("Annotation key")),
FacetSelector::Binding(keys) => if layer == Layer::Oa { keys.oa } else { keys.sa }
.map(|id| serde_json::to_value(id).expect("Binding key")),
_ => None,
}
}
pub(super) fn overlap(a: &FacetSelector, b: &FacetSelector) -> bool {
if family(a).is_none() || family(a) != family(b) {
return false;
}
[Layer::Oa, Layer::Sa]
.into_iter()
.any(|layer| key(a, layer).is_some() && key(a, layer) == key(b, layer))
}
pub(super) fn project_presence(
value: &mut Value,
facet: &FacetSelector,
layer: Layer,
present: bool,
) -> Result<(), String> {
let family = family(facet).ok_or("This keyed family remains read-only.")?;
let key = key(facet, layer)
.ok_or("Choose the destination identity in Members before setting or taking presence.")?;
let path =
path(value, family).ok_or("This collection is not applicable to the destination kind.")?;
let list = value
.pointer_mut(&path)
.and_then(Value::as_array_mut)
.ok_or("Destination collection is unavailable.")?;
if present {
if !list.contains(&key) {
list.push(key);
}
} else {
list.retain(|v| v != &key);
}
Ok(())
}
impl ReviewRow {
pub(super) fn keyed_value(
&self,
project: &Project,
trace: &Trace,
value: &mut Value,
facet: &FacetSelector,
decision: SemanticDecision,
) -> Result<(), String> {
if keyed_rows::supported(facet) {
return self.project_row(project, trace, value, facet, decision);
}
let present = match decision {
SemanticDecision::KeepTarget => return Ok(()),
SemanticDecision::TakeSource => {
// A missing source identity is a target-local row, not a removal.
if key(facet, self.direction.source_layer()).is_none() {
return Ok(());
}
let fact = capture_facet(project, trace.oa, trace.sa, facet)?;
scalar::value(&fact, self.direction.source_layer()).and_then(|v| v.as_bool()).ok_or("Source collection is not applicable; choose an explicit final presence or Keep.")?
}
SemanticDecision::Candidate => *self
.presence
.get(facet)
.ok_or("Choose final membership presence.")?,
};
project_presence(value, facet, self.direction.target_layer(), present)
}
pub(super) fn member_families(&self, project: &Project) -> Vec<Family> {
let Some(trace) = self.effective_trace(project) else {
return vec![];
};
let values: Vec<_> = [trace.oa, trace.sa]
.into_iter()
.filter_map(|id| Draft::from_project(project, id).map(|d| d.value))
.collect();
FAMILIES
.into_iter()
.filter(|family| values.iter().any(|value| path(value, *family).is_some()))
.collect()
}
pub(super) fn member_choices(&self, project: &Project, layer: Layer) -> Vec<Choice> {
if self.member_family == Family::Binding {
return self.binding_choices(project, layer, true);
}
let Some(trace) = self.effective_trace(project) else {
return vec![];
};
let id = if layer == Layer::Oa {
trace.oa
} else {
trace.sa
};
let Some(mut draft) = Draft::from_project(project, id) else {
return vec![];
};
if layer == self.direction.target_layer() {
draft.set_context(self.combined_value(project, true).ok());
}
let selected = if layer == Layer::Oa {
&self.member_oa
} else {
&self.member_sa
};
let Some(path) = path(&draft.context_value(), self.member_family) else {
return selected.iter().cloned().collect();
};
crate::forms::reference_choices(
&draft,
project,
&format!("{path}/0"),
selected.as_ref().map_or(Id::nil(), |c| c.id),
)
.into_iter()
.filter(|c| !c.id.is_nil())
.collect()
}
pub(super) fn edit_pair(
&mut self,
project: &Project,
facet: FacetSelector,
) -> Result<(), String> {
self.member_family = family(&facet).ok_or("This keyed family remains read-only.")?;
match facet {
FacetSelector::Annotation(keys) => {
self.annotation_oa.selected = keys.oa.map(|key| crate::data_values::FieldPathKey {
path: key.path,
field: key.field,
});
self.annotation_sa.selected = keys.sa.map(|key| crate::data_values::FieldPathKey {
path: key.path,
field: key.field,
});
}
FacetSelector::Binding(keys) => {
self.member_oa = keys.oa.map(|id| view::choice(project, id));
self.member_sa = keys.sa.map(|id| view::choice(project, id));
}
FacetSelector::Member { keys, .. } => {
self.member_oa = keys.oa.map(|id| view::choice(project, id));
self.member_sa = keys.sa.map(|id| view::choice(project, id));
}
FacetSelector::Literal(keys) => {
self.literal_oa = keys.oa.is_some();
self.literal_sa = keys.sa.is_some();
self.literal = keys.oa.or(keys.sa).unwrap_or_default();
}
_ => unreachable!(),
}
self.tab = Tab::Members;
Ok(())
}
pub(super) fn stage_member(&mut self, project: &Project) -> Result<(), String> {
if !FAMILIES.contains(&self.member_family) {
return Err("This keyed family remains read-only.".into());
}
let facet = match self.member_family {
Family::Member(collection) => FacetSelector::Member {
collection,
keys: KeyPair {
oa: self.member_oa.as_ref().map(|c| c.id),
sa: self.member_sa.as_ref().map(|c| c.id),
},
},
Family::Literal => FacetSelector::Literal(KeyPair {
oa: self.literal_oa.then(|| self.literal.clone()),
sa: self.literal_sa.then(|| self.literal.clone()),
}),
Family::Annotation => FacetSelector::Annotation(KeyPair {
oa: self
.annotation_oa
.selected
.as_ref()
.map(|key| AnnotationKey {
path: key.path.clone(),
field: key.field,
}),
sa: self
.annotation_sa
.selected
.as_ref()
.map(|key| AnnotationKey {
path: key.path.clone(),
field: key.field,
}),
}),
Family::Binding => FacetSelector::Binding(KeyPair {
oa: self.member_oa.as_ref().map(|c| c.id),
sa: self.member_sa.as_ref().map(|c| c.id),
}),
};
let trace = self.effective_trace(project).ok_or("Choose a trace.")?;
capture_facet(project, trace.oa, trace.sa, &facet)?;
self.stage_row_references(&facet)?;
if let FacetSelector::Member {
keys:
KeyPair {
oa: Some(oa),
sa: Some(sa),
},
..
} = &facet
{
self.references.insert(*oa, *sa);
}
self.staged.insert(facet.clone());
self.selected = Some(facet);
self.tab = Tab::Facts;
Ok(())
}
}
@@ -1,345 +1,345 @@
//! Atomic message-value and lifeline-binding rows with exact, immutable keys.
use super::*;
use crate::data_values::{FieldPathChoice, FieldPathKey};
#[derive(Default)]
pub struct AddressDraft {
pub selected: Option<FieldPathKey>,
pub scope: Option<FieldPathKey>,
pub page: usize,
}
#[derive(Default)]
pub struct RowDraft {
pub expression: String,
pub editor: text_editor::Content,
pub local: Option<Choice>,
}
pub(super) fn supported(facet: &FacetSelector) -> bool {
matches!(
facet,
FacetSelector::Annotation(_) | FacetSelector::Binding(_)
)
}
pub(super) fn target_selector(facet: &FacetSelector, layer: Layer) -> FacetSelector {
match facet {
FacetSelector::Annotation(keys) => FacetSelector::Annotation(KeyPair {
oa: (layer == Layer::Oa).then(|| keys.oa.clone()).flatten(),
sa: (layer == Layer::Sa).then(|| keys.sa.clone()).flatten(),
}),
FacetSelector::Binding(keys) => FacetSelector::Binding(KeyPair {
oa: if layer == Layer::Oa { keys.oa } else { None },
sa: if layer == Layer::Sa { keys.sa } else { None },
}),
_ => facet.clone(),
}
}
impl ReviewRow {
pub(super) fn annotation_address(&self, layer: Layer) -> &AddressDraft {
if layer == Layer::Oa {
&self.annotation_oa
} else {
&self.annotation_sa
}
}
pub(super) fn annotation_address_mut(&mut self, layer: Layer) -> &mut AddressDraft {
if layer == Layer::Oa {
&mut self.annotation_oa
} else {
&mut self.annotation_sa
}
}
fn row_owner(&self, project: &Project, layer: Layer) -> Option<Element> {
let trace = self.effective_trace(project)?;
let id = if layer == Layer::Oa {
trace.oa
} else {
trace.sa
};
if layer == self.direction.target_layer()
&& let Ok(value) = self.combined_value(project, true)
&& let Ok(element) = serde_json::from_value(value)
{
return Some(element);
}
project.elements.get(&id).cloned()
}
pub(super) fn annotation_choices(
&self,
project: &Project,
layer: Layer,
) -> Result<Vec<FieldPathChoice>, String> {
let element = self.row_owner(project, layer).ok_or("Choose a trace.")?;
let Some(SharedBody::Occurrence {
body:
OccurrenceBody::Exchange {
exchange: Some(exchange),
message_kind,
..
},
..
}) = element.shared()
else {
return Err(
"Choose an exchange on this message before selecting a carried field.".into(),
);
};
let exchange = project
.relations
.get(exchange)
.ok_or("The message exchange is unavailable.")?;
crate::data_values::at_scope(
project,
exchange,
message_kind,
self.annotation_address(layer).scope.as_ref(),
)
}
pub(super) fn binding_choices(
&self,
project: &Project,
layer: Layer,
referenced: bool,
) -> Vec<Choice> {
let Some(element) = self.row_owner(project, layer) else {
return vec![];
};
let scenario = if referenced {
match element.shared() {
Some(SharedBody::Occurrence {
body: OccurrenceBody::ScenarioUse { scenario, .. },
..
}) => *scenario,
_ => None,
}
} else {
element
.parent
.and_then(|parent| validation::ancestor_of_kind(project, parent, Kind::Scenario))
};
let mut choices: Vec<_> = project
.elements
.values()
.filter(|e| {
e.kind() == Kind::Lifeline
&& e.layer() == layer
&& scenario.is_some()
&& e.parent == scenario
})
.map(|e| view::choice(project, e.id))
.collect();
choices.sort_by_cached_key(|c| c.label.to_lowercase());
choices
}
pub(super) fn stage_row_references(&mut self, facet: &FacetSelector) -> Result<(), String> {
let pairs: Vec<_> = match facet {
FacetSelector::Annotation(KeyPair {
oa: Some(oa),
sa: Some(sa),
}) => {
if oa.path.len() != sa.path.len() {
return Err("Paired annotation paths must have the same depth; review distinct addresses separately.".into());
}
oa.path
.iter()
.chain(std::iter::once(&oa.field))
.copied()
.zip(sa.path.iter().chain(std::iter::once(&sa.field)).copied())
.collect()
}
FacetSelector::Binding(KeyPair {
oa: Some(oa),
sa: Some(sa),
}) => vec![(*oa, *sa)],
_ => vec![],
};
// A repeated recursive field may occur several times in one address.
// Never let the last occurrence silently replace a conflicting pair.
let mut supplied = BTreeMap::new();
for (oa, sa) in pairs {
if supplied.insert(oa, sa).is_some_and(|prior| prior != sa) {
return Err(
"This address pairs the same Operational field with different System fields."
.into(),
);
}
}
self.references.extend(supplied);
Ok(())
}
pub(super) fn initialize_row(&mut self, project: &Project, facet: &FacetSelector) {
if self.row_drafts.contains_key(facet) {
return;
}
let value = self
.effective_trace(project)
.and_then(|t| capture_facet(project, t.oa, t.sa, facet).ok())
.and_then(|f| scalar::value(&f, self.direction.target_layer()));
let present = value.as_ref().is_some_and(|v| !v.is_null());
let mut draft = RowDraft::default();
if let Some(value) = value {
draft.expression = value["expression"].as_str().unwrap_or_default().into();
draft.editor = text_editor::Content::with_text(&draft.expression);
draft.local = value["local"]
.as_str()
.and_then(|v| v.parse().ok())
.map(|id| view::choice(project, id));
}
self.presence.entry(facet.clone()).or_insert(present);
self.row_drafts.insert(facet.clone(), draft);
}
pub(super) fn edit_row(
&mut self,
facet: &FacetSelector,
action: impl FnOnce(&mut RowDraft),
) -> Result<(), String> {
if !supported(facet)
|| self.selected.as_ref() != Some(facet)
|| self.decisions.get(facet) != Some(&SemanticDecision::Candidate)
{
return Err("Select this row and choose Set final value before editing it.".into());
}
action(
self.row_drafts
.get_mut(facet)
.ok_or("The row draft is unavailable.")?,
);
Ok(())
}
pub(super) fn project_row(
&self,
project: &Project,
trace: &Trace,
value: &mut Value,
facet: &FacetSelector,
decision: SemanticDecision,
) -> Result<(), String> {
if decision == SemanticDecision::KeepTarget {
return Ok(());
}
let source_layer = self.direction.source_layer();
let target_layer = self.direction.target_layer();
if decision == SemanticDecision::TakeSource && keyed::key(facet, source_layer).is_none() {
return Ok(());
}
let target_key = keyed::key(facet, target_layer)
.ok_or("Choose the destination row address before setting or taking its value.")?;
let row = if decision == SemanticDecision::Candidate {
if !self.presence.get(facet).copied().unwrap_or(false) {
Value::Null
} else {
let draft = self
.row_drafts
.get(facet)
.ok_or("Set the final row value.")?;
match facet {
FacetSelector::Annotation(_) => {
let key: AnnotationKey = serde_json::from_value(target_key.clone())
.map_err(|e| e.to_string())?;
serde_json::to_value(MessageValue {
path: key.path,
field: key.field,
expression: draft.expression.clone(),
})
.expect("Message value")
}
FacetSelector::Binding(_) => {
serde_json::json!({"referenced": target_key, "local": draft.local.as_ref().ok_or("Choose the destination scenario's local lifeline.")?.id})
}
_ => return Err("Unsupported row.".into()),
}
}
} else {
let fact = capture_facet(project, trace.oa, trace.sa, facet)?;
let row = scalar::value(&fact, source_layer)
.ok_or("Source row collection is not applicable; review its constructor first.")?;
if row.is_null() {
row
} else {
let map = |id: Id| -> Result<Id, String> {
if source_layer == Layer::Oa {
self.references.get(&id).copied().ok_or_else(|| {
format!("Choose a reference counterpart for {}.", project.named(id))
})
} else {
let matches: Vec<_> = self
.references
.iter()
.filter(|(_, sa)| **sa == id)
.map(|(oa, _)| *oa)
.collect();
if matches.len() == 1 {
Ok(matches[0])
} else {
Err(format!(
"Choose one unambiguous reference counterpart for {}.",
project.named(id)
))
}
}
};
match facet {
FacetSelector::Annotation(_) => {
let mut row: MessageValue =
serde_json::from_value(row).map_err(|e| e.to_string())?;
row.path = row.path.into_iter().map(map).collect::<Result<_, _>>()?;
row.field = map(row.field)?;
if serde_json::to_value(AnnotationKey::from(&row)).expect("key")
!= target_key
{
return Err("Mapped annotation address disagrees with the selected destination address.".into());
}
serde_json::to_value(row).expect("row")
}
FacetSelector::Binding(_) => {
let row: LifelineBinding =
serde_json::from_value(row).map_err(|e| e.to_string())?;
let mapped = LifelineBinding {
referenced: map(row.referenced)?,
local: map(row.local)?,
};
if serde_json::to_value(mapped.referenced).expect("Id") != target_key {
return Err("Mapped binding key disagrees with the selected destination lifeline.".into());
}
serde_json::to_value(mapped).expect("row")
}
_ => return Err("Unsupported row.".into()),
}
}
};
let family = keyed::family(facet).ok_or("Unsupported row.")?;
let path = keyed::path(value, family)
.ok_or("The destination constructor has no collection for this row.")?;
let rows = value
.pointer_mut(&path)
.and_then(Value::as_array_mut)
.ok_or("Destination rows are unavailable.")?;
let position = rows.iter().position(|row| match facet {
FacetSelector::Annotation(_) => {
serde_json::json!({"path": row["path"], "field": row["field"]}) == target_key
}
FacetSelector::Binding(_) => row["referenced"] == target_key,
_ => false,
});
match (position, row.is_null()) {
(Some(index), false) => rows[index] = row,
(Some(index), true) => {
rows.remove(index);
}
(None, false) => rows.push(row),
(None, true) => {}
}
Ok(())
}
}
//! Atomic message-value and lifeline-binding rows with exact, immutable keys.
use super::*;
use crate::data_values::{FieldPathChoice, FieldPathKey};
#[derive(Default)]
pub struct AddressDraft {
pub selected: Option<FieldPathKey>,
pub scope: Option<FieldPathKey>,
pub page: usize,
}
#[derive(Default)]
pub struct RowDraft {
pub expression: String,
pub editor: text_editor::Content,
pub local: Option<Choice>,
}
pub(super) fn supported(facet: &FacetSelector) -> bool {
matches!(
facet,
FacetSelector::Annotation(_) | FacetSelector::Binding(_)
)
}
pub(super) fn target_selector(facet: &FacetSelector, layer: Layer) -> FacetSelector {
match facet {
FacetSelector::Annotation(keys) => FacetSelector::Annotation(KeyPair {
oa: (layer == Layer::Oa).then(|| keys.oa.clone()).flatten(),
sa: (layer == Layer::Sa).then(|| keys.sa.clone()).flatten(),
}),
FacetSelector::Binding(keys) => FacetSelector::Binding(KeyPair {
oa: if layer == Layer::Oa { keys.oa } else { None },
sa: if layer == Layer::Sa { keys.sa } else { None },
}),
_ => facet.clone(),
}
}
impl ReviewRow {
pub(super) fn annotation_address(&self, layer: Layer) -> &AddressDraft {
if layer == Layer::Oa {
&self.annotation_oa
} else {
&self.annotation_sa
}
}
pub(super) fn annotation_address_mut(&mut self, layer: Layer) -> &mut AddressDraft {
if layer == Layer::Oa {
&mut self.annotation_oa
} else {
&mut self.annotation_sa
}
}
fn row_owner(&self, project: &Project, layer: Layer) -> Option<Element> {
let trace = self.effective_trace(project)?;
let id = if layer == Layer::Oa {
trace.oa
} else {
trace.sa
};
if layer == self.direction.target_layer()
&& let Ok(value) = self.combined_value(project, true)
&& let Ok(element) = serde_json::from_value(value)
{
return Some(element);
}
project.elements.get(&id).cloned()
}
pub(super) fn annotation_choices(
&self,
project: &Project,
layer: Layer,
) -> Result<Vec<FieldPathChoice>, String> {
let element = self.row_owner(project, layer).ok_or("Choose a trace.")?;
let Some(SharedBody::Occurrence {
body:
OccurrenceBody::Exchange {
exchange: Some(exchange),
message_kind,
..
},
..
}) = element.shared()
else {
return Err(
"Choose an exchange on this message before selecting a carried field.".into(),
);
};
let exchange = project
.relations
.get(exchange)
.ok_or("The message exchange is unavailable.")?;
crate::data_values::at_scope(
project,
exchange,
message_kind,
self.annotation_address(layer).scope.as_ref(),
)
}
pub(super) fn binding_choices(
&self,
project: &Project,
layer: Layer,
referenced: bool,
) -> Vec<Choice> {
let Some(element) = self.row_owner(project, layer) else {
return vec![];
};
let scenario = if referenced {
match element.shared() {
Some(SharedBody::Occurrence {
body: OccurrenceBody::ScenarioUse { scenario, .. },
..
}) => *scenario,
_ => None,
}
} else {
element
.parent
.and_then(|parent| validation::ancestor_of_kind(project, parent, Kind::Scenario))
};
let mut choices: Vec<_> = project
.elements
.values()
.filter(|e| {
e.kind() == Kind::Lifeline
&& e.layer() == layer
&& scenario.is_some()
&& e.parent == scenario
})
.map(|e| view::choice(project, e.id))
.collect();
choices.sort_by_cached_key(|c| c.label.to_lowercase());
choices
}
pub(super) fn stage_row_references(&mut self, facet: &FacetSelector) -> Result<(), String> {
let pairs: Vec<_> = match facet {
FacetSelector::Annotation(KeyPair {
oa: Some(oa),
sa: Some(sa),
}) => {
if oa.path.len() != sa.path.len() {
return Err("Paired annotation paths must have the same depth; review distinct addresses separately.".into());
}
oa.path
.iter()
.chain(std::iter::once(&oa.field))
.copied()
.zip(sa.path.iter().chain(std::iter::once(&sa.field)).copied())
.collect()
}
FacetSelector::Binding(KeyPair {
oa: Some(oa),
sa: Some(sa),
}) => vec![(*oa, *sa)],
_ => vec![],
};
// A repeated recursive field may occur several times in one address.
// Never let the last occurrence silently replace a conflicting pair.
let mut supplied = BTreeMap::new();
for (oa, sa) in pairs {
if supplied.insert(oa, sa).is_some_and(|prior| prior != sa) {
return Err(
"This address pairs the same Operational field with different System fields."
.into(),
);
}
}
self.references.extend(supplied);
Ok(())
}
pub(super) fn initialize_row(&mut self, project: &Project, facet: &FacetSelector) {
if self.row_drafts.contains_key(facet) {
return;
}
let value = self
.effective_trace(project)
.and_then(|t| capture_facet(project, t.oa, t.sa, facet).ok())
.and_then(|f| scalar::value(&f, self.direction.target_layer()));
let present = value.as_ref().is_some_and(|v| !v.is_null());
let mut draft = RowDraft::default();
if let Some(value) = value {
draft.expression = value["expression"].as_str().unwrap_or_default().into();
draft.editor = text_editor::Content::with_text(&draft.expression);
draft.local = value["local"]
.as_str()
.and_then(|v| v.parse().ok())
.map(|id| view::choice(project, id));
}
self.presence.entry(facet.clone()).or_insert(present);
self.row_drafts.insert(facet.clone(), draft);
}
pub(super) fn edit_row(
&mut self,
facet: &FacetSelector,
action: impl FnOnce(&mut RowDraft),
) -> Result<(), String> {
if !supported(facet)
|| self.selected.as_ref() != Some(facet)
|| self.decisions.get(facet) != Some(&SemanticDecision::Candidate)
{
return Err("Select this row and choose Set final value before editing it.".into());
}
action(
self.row_drafts
.get_mut(facet)
.ok_or("The row draft is unavailable.")?,
);
Ok(())
}
pub(super) fn project_row(
&self,
project: &Project,
trace: &Trace,
value: &mut Value,
facet: &FacetSelector,
decision: SemanticDecision,
) -> Result<(), String> {
if decision == SemanticDecision::KeepTarget {
return Ok(());
}
let source_layer = self.direction.source_layer();
let target_layer = self.direction.target_layer();
if decision == SemanticDecision::TakeSource && keyed::key(facet, source_layer).is_none() {
return Ok(());
}
let target_key = keyed::key(facet, target_layer)
.ok_or("Choose the destination row address before setting or taking its value.")?;
let row = if decision == SemanticDecision::Candidate {
if !self.presence.get(facet).copied().unwrap_or(false) {
Value::Null
} else {
let draft = self
.row_drafts
.get(facet)
.ok_or("Set the final row value.")?;
match facet {
FacetSelector::Annotation(_) => {
let key: AnnotationKey = serde_json::from_value(target_key.clone())
.map_err(|e| e.to_string())?;
serde_json::to_value(MessageValue {
path: key.path,
field: key.field,
expression: draft.expression.clone(),
})
.expect("Message value")
}
FacetSelector::Binding(_) => {
serde_json::json!({"referenced": target_key, "local": draft.local.as_ref().ok_or("Choose the destination scenario's local lifeline.")?.id})
}
_ => return Err("Unsupported row.".into()),
}
}
} else {
let fact = capture_facet(project, trace.oa, trace.sa, facet)?;
let row = scalar::value(&fact, source_layer)
.ok_or("Source row collection is not applicable; review its constructor first.")?;
if row.is_null() {
row
} else {
let map = |id: Id| -> Result<Id, String> {
if source_layer == Layer::Oa {
self.references.get(&id).copied().ok_or_else(|| {
format!("Choose a reference counterpart for {}.", project.named(id))
})
} else {
let matches: Vec<_> = self
.references
.iter()
.filter(|(_, sa)| **sa == id)
.map(|(oa, _)| *oa)
.collect();
if matches.len() == 1 {
Ok(matches[0])
} else {
Err(format!(
"Choose one unambiguous reference counterpart for {}.",
project.named(id)
))
}
}
};
match facet {
FacetSelector::Annotation(_) => {
let mut row: MessageValue =
serde_json::from_value(row).map_err(|e| e.to_string())?;
row.path = row.path.into_iter().map(map).collect::<Result<_, _>>()?;
row.field = map(row.field)?;
if serde_json::to_value(AnnotationKey::from(&row)).expect("key")
!= target_key
{
return Err("Mapped annotation address disagrees with the selected destination address.".into());
}
serde_json::to_value(row).expect("row")
}
FacetSelector::Binding(_) => {
let row: LifelineBinding =
serde_json::from_value(row).map_err(|e| e.to_string())?;
let mapped = LifelineBinding {
referenced: map(row.referenced)?,
local: map(row.local)?,
};
if serde_json::to_value(mapped.referenced).expect("Id") != target_key {
return Err("Mapped binding key disagrees with the selected destination lifeline.".into());
}
serde_json::to_value(mapped).expect("row")
}
_ => return Err("Unsupported row.".into()),
}
}
};
let family = keyed::family(facet).ok_or("Unsupported row.")?;
let path = keyed::path(value, family)
.ok_or("The destination constructor has no collection for this row.")?;
let rows = value
.pointer_mut(&path)
.and_then(Value::as_array_mut)
.ok_or("Destination rows are unavailable.")?;
let position = rows.iter().position(|row| match facet {
FacetSelector::Annotation(_) => {
serde_json::json!({"path": row["path"], "field": row["field"]}) == target_key
}
FacetSelector::Binding(_) => row["referenced"] == target_key,
_ => false,
});
match (position, row.is_null()) {
(Some(index), false) => rows[index] = row,
(Some(index), true) => {
rows.remove(index);
}
(None, false) => rows.push(row),
(None, true) => {}
}
Ok(())
}
}
File diff suppressed because it is too large Load Diff
+254 -254
View File
@@ -1,254 +1,254 @@
//! Independent membership and complete final order; the core validates every proposal.
use super::*;
pub(super) fn collection(which: OrderedCollection) -> ReferenceCollection {
match which {
OrderedCollection::Steps => ReferenceCollection::Steps,
OrderedCollection::FragmentBranches => ReferenceCollection::FragmentBranches,
}
}
pub(super) fn ordered(which: ReferenceCollection) -> Option<OrderedCollection> {
match which {
ReferenceCollection::Steps => Some(OrderedCollection::Steps),
ReferenceCollection::FragmentBranches => Some(OrderedCollection::FragmentBranches),
_ => None,
}
}
pub(super) fn read(value: &Value, which: OrderedCollection) -> Result<Vec<Id>, String> {
let path = keyed::path(value, keyed::Family::Member(collection(which)))
.ok_or("This ordered collection is unavailable on the destination.")?;
serde_json::from_value(value.pointer(&path).unwrap().clone()).map_err(|e| e.to_string())
}
fn write(value: &mut Value, which: OrderedCollection, ids: Vec<Id>) -> Result<(), String> {
let path = keyed::path(value, keyed::Family::Member(collection(which)))
.ok_or("This ordered collection is unavailable on the destination.")?;
*value.pointer_mut(&path).unwrap() = serde_json::to_value(ids).expect("Ordered identities");
Ok(())
}
impl ReviewRow {
pub(super) fn ordered_members(
&self,
project: &Project,
which: OrderedCollection,
) -> Result<Vec<Id>, String> {
read(&self.combine(project, true, true)?, which)
}
pub(super) fn initialize_order(
&mut self,
project: &Project,
which: OrderedCollection,
) -> Result<(), String> {
if !self.order_drafts.contains_key(&which) {
let ids = self.ordered_members(project, which)?;
self.order_drafts.insert(which, ids);
}
Ok(())
}
pub(super) fn reconcile_order(
&mut self,
project: &Project,
which: OrderedCollection,
) -> Result<(), String> {
self.require_order_candidate(which)?;
let members = self.ordered_members(project, which)?;
let draft = self
.order_drafts
.get_mut(&which)
.ok_or("Choose a final order first.")?;
// This is an explicit user action. Ordinary refresh never discards an authored order.
let mut seen = BTreeSet::new();
draft.retain(|id| members.contains(id) && seen.insert(*id));
for id in members {
if seen.insert(id) {
draft.push(id);
}
}
Ok(())
}
fn require_order_candidate(&self, which: OrderedCollection) -> Result<(), String> {
let facet = FacetSelector::Order(which);
if self.selected.as_ref() != Some(&facet)
|| self.decisions.get(&facet) != Some(&SemanticDecision::Candidate)
{
return Err("Select Set final value for this order before changing it.".into());
}
Ok(())
}
pub(super) fn move_order(
&mut self,
which: OrderedCollection,
index: usize,
delta: i32,
) -> Result<(), String> {
self.require_order_candidate(which)?;
let ids = self
.order_drafts
.get_mut(&which)
.ok_or("Choose a final order first.")?;
let destination = match delta {
-1 => index.checked_sub(1),
1 => index.checked_add(1),
_ => None,
};
let destination = destination
.filter(|i| index < ids.len() && *i < ids.len())
.ok_or("Choose an existing adjacent position in the final order.")?;
ids.swap(index, destination);
Ok(())
}
pub(super) fn project_order(
&self,
project: &Project,
trace: &Trace,
value: &mut Value,
which: OrderedCollection,
decision: SemanticDecision,
) -> Result<(), String> {
let current = read(value, which)?;
let supplied = match decision {
SemanticDecision::KeepTarget => return Ok(()),
SemanticDecision::Candidate => self
.order_drafts
.get(&which)
.cloned()
.ok_or("Choose a final order.")?,
SemanticDecision::TakeSource => {
let fact =
capture_facet(project, trace.oa, trace.sa, &FacetSelector::Order(which))?;
let source: Vec<Id> = serde_json::from_value(
scalar::value(&fact, self.direction.source_layer())
.ok_or("The source has no applicable order.")?,
)
.map_err(|e| e.to_string())?;
let map = self.order_reference_map()?;
source
.into_iter()
.map(|id| {
map.get(&id).copied().ok_or_else(|| {
format!(
"Pair source order member {} explicitly in Reference pairs.",
project.named(id)
)
})
})
.collect::<Result<Vec<_>, _>>()?
}
};
let actual: BTreeSet<_> = current.iter().copied().collect();
let desired: BTreeSet<_> = supplied.iter().copied().collect();
if desired.len() != supplied.len() {
return Err(
"The final order contains a duplicate identity; reconcile its members explicitly."
.into(),
);
}
if desired != actual {
if decision == SemanticDecision::TakeSource
&& desired.is_subset(&actual)
&& current
.iter()
.filter(|id| desired.contains(id))
.copied()
.collect::<Vec<_>>()
== supplied
{
return Ok(());
}
return Err("Final order must contain every surviving destination member exactly once. Reconcile members, then choose their positions; membership is reviewed separately.".into());
}
write(value, which, supplied)
}
fn order_reference_map(&self) -> Result<BTreeMap<Id, Id>, String> {
let mut map = BTreeMap::new();
for (oa, sa) in &self.references {
let (a, b) = if self.direction == TransitionDirection::OaToSa {
(*oa, *sa)
} else {
(*sa, *oa)
};
if map.insert(a, b).is_some_and(|old| old != b) {
return Err("Reverse reference correspondence is ambiguous.".into());
}
}
Ok(map)
}
pub(super) fn project_ordered_member(
&self,
project: &Project,
trace: &Trace,
value: &mut Value,
facet: &FacetSelector,
decision: SemanticDecision,
form_context: bool,
) -> Result<(), String> {
let FacetSelector::Member {
collection: member_collection,
keys,
} = facet
else {
unreachable!()
};
let which = ordered(*member_collection).expect("Ordered member");
let before = read(value, which)?;
self.keyed_value(project, trace, value, facet, decision)?;
let after = read(value, which)?;
let explicit = self
.decisions
.get(&FacetSelector::Order(which))
.is_some_and(|d| *d != SemanticDecision::KeepTarget);
if decision != SemanticDecision::TakeSource || explicit || after.len() <= before.len() {
return Ok(());
}
let (source_key, target_key) = if self.direction == TransitionDirection::OaToSa {
(keys.oa, keys.sa)
} else {
(keys.sa, keys.oa)
};
let (Some(source_key), Some(target_key)) = (source_key, target_key) else {
return Ok(());
};
let fact = capture_facet(project, trace.oa, trace.sa, &FacetSelector::Order(which))?;
let source: Vec<Id> = serde_json::from_value(
scalar::value(&fact, self.direction.source_layer())
.ok_or("Source order is unavailable.")?,
)
.map_err(|e| e.to_string())?;
let position = source
.iter()
.position(|id| *id == source_key)
.ok_or("Source member is absent.")?;
let map = self.order_reference_map()?;
let anchor = |id: &Id| {
map.get(id)
.and_then(|mapped| before.iter().position(|id| id == mapped))
};
let left = source[..position].iter().rev().find_map(anchor);
let right = source[position + 1..].iter().find_map(anchor);
let at = match (left, right) {
(Some(a), Some(b)) if a + 1 == b => Some(b),
(Some(a), None) if a + 1 == before.len() => Some(a + 1),
(None, Some(0)) => Some(0),
(None, None) if before.is_empty() => Some(0),
_ => None,
};
if let Some(at) = at {
let mut ordered = before;
ordered.insert(at, target_key);
write(value, which, ordered)
} else if form_context {
// An uncommitted membership list lets the user author a final order.
// The actual request still rejects ambiguous placement until explicitly decided.
Ok(())
} else {
Err("Ordered member insertion has no unique unchanged anchor; select an explicit final Order in Properties.".into())
}
}
}
//! Independent membership and complete final order; the core validates every proposal.
use super::*;
pub(super) fn collection(which: OrderedCollection) -> ReferenceCollection {
match which {
OrderedCollection::Steps => ReferenceCollection::Steps,
OrderedCollection::FragmentBranches => ReferenceCollection::FragmentBranches,
}
}
pub(super) fn ordered(which: ReferenceCollection) -> Option<OrderedCollection> {
match which {
ReferenceCollection::Steps => Some(OrderedCollection::Steps),
ReferenceCollection::FragmentBranches => Some(OrderedCollection::FragmentBranches),
_ => None,
}
}
pub(super) fn read(value: &Value, which: OrderedCollection) -> Result<Vec<Id>, String> {
let path = keyed::path(value, keyed::Family::Member(collection(which)))
.ok_or("This ordered collection is unavailable on the destination.")?;
serde_json::from_value(value.pointer(&path).unwrap().clone()).map_err(|e| e.to_string())
}
fn write(value: &mut Value, which: OrderedCollection, ids: Vec<Id>) -> Result<(), String> {
let path = keyed::path(value, keyed::Family::Member(collection(which)))
.ok_or("This ordered collection is unavailable on the destination.")?;
*value.pointer_mut(&path).unwrap() = serde_json::to_value(ids).expect("Ordered identities");
Ok(())
}
impl ReviewRow {
pub(super) fn ordered_members(
&self,
project: &Project,
which: OrderedCollection,
) -> Result<Vec<Id>, String> {
read(&self.combine(project, true, true)?, which)
}
pub(super) fn initialize_order(
&mut self,
project: &Project,
which: OrderedCollection,
) -> Result<(), String> {
if !self.order_drafts.contains_key(&which) {
let ids = self.ordered_members(project, which)?;
self.order_drafts.insert(which, ids);
}
Ok(())
}
pub(super) fn reconcile_order(
&mut self,
project: &Project,
which: OrderedCollection,
) -> Result<(), String> {
self.require_order_candidate(which)?;
let members = self.ordered_members(project, which)?;
let draft = self
.order_drafts
.get_mut(&which)
.ok_or("Choose a final order first.")?;
// This is an explicit user action. Ordinary refresh never discards an authored order.
let mut seen = BTreeSet::new();
draft.retain(|id| members.contains(id) && seen.insert(*id));
for id in members {
if seen.insert(id) {
draft.push(id);
}
}
Ok(())
}
fn require_order_candidate(&self, which: OrderedCollection) -> Result<(), String> {
let facet = FacetSelector::Order(which);
if self.selected.as_ref() != Some(&facet)
|| self.decisions.get(&facet) != Some(&SemanticDecision::Candidate)
{
return Err("Select Set final value for this order before changing it.".into());
}
Ok(())
}
pub(super) fn move_order(
&mut self,
which: OrderedCollection,
index: usize,
delta: i32,
) -> Result<(), String> {
self.require_order_candidate(which)?;
let ids = self
.order_drafts
.get_mut(&which)
.ok_or("Choose a final order first.")?;
let destination = match delta {
-1 => index.checked_sub(1),
1 => index.checked_add(1),
_ => None,
};
let destination = destination
.filter(|i| index < ids.len() && *i < ids.len())
.ok_or("Choose an existing adjacent position in the final order.")?;
ids.swap(index, destination);
Ok(())
}
pub(super) fn project_order(
&self,
project: &Project,
trace: &Trace,
value: &mut Value,
which: OrderedCollection,
decision: SemanticDecision,
) -> Result<(), String> {
let current = read(value, which)?;
let supplied = match decision {
SemanticDecision::KeepTarget => return Ok(()),
SemanticDecision::Candidate => self
.order_drafts
.get(&which)
.cloned()
.ok_or("Choose a final order.")?,
SemanticDecision::TakeSource => {
let fact =
capture_facet(project, trace.oa, trace.sa, &FacetSelector::Order(which))?;
let source: Vec<Id> = serde_json::from_value(
scalar::value(&fact, self.direction.source_layer())
.ok_or("The source has no applicable order.")?,
)
.map_err(|e| e.to_string())?;
let map = self.order_reference_map()?;
source
.into_iter()
.map(|id| {
map.get(&id).copied().ok_or_else(|| {
format!(
"Pair source order member {} explicitly in Reference pairs.",
project.named(id)
)
})
})
.collect::<Result<Vec<_>, _>>()?
}
};
let actual: BTreeSet<_> = current.iter().copied().collect();
let desired: BTreeSet<_> = supplied.iter().copied().collect();
if desired.len() != supplied.len() {
return Err(
"The final order contains a duplicate identity; reconcile its members explicitly."
.into(),
);
}
if desired != actual {
if decision == SemanticDecision::TakeSource
&& desired.is_subset(&actual)
&& current
.iter()
.filter(|id| desired.contains(id))
.copied()
.collect::<Vec<_>>()
== supplied
{
return Ok(());
}
return Err("Final order must contain every surviving destination member exactly once. Reconcile members, then choose their positions; membership is reviewed separately.".into());
}
write(value, which, supplied)
}
fn order_reference_map(&self) -> Result<BTreeMap<Id, Id>, String> {
let mut map = BTreeMap::new();
for (oa, sa) in &self.references {
let (a, b) = if self.direction == TransitionDirection::OaToSa {
(*oa, *sa)
} else {
(*sa, *oa)
};
if map.insert(a, b).is_some_and(|old| old != b) {
return Err("Reverse reference correspondence is ambiguous.".into());
}
}
Ok(map)
}
pub(super) fn project_ordered_member(
&self,
project: &Project,
trace: &Trace,
value: &mut Value,
facet: &FacetSelector,
decision: SemanticDecision,
form_context: bool,
) -> Result<(), String> {
let FacetSelector::Member {
collection: member_collection,
keys,
} = facet
else {
unreachable!()
};
let which = ordered(*member_collection).expect("Ordered member");
let before = read(value, which)?;
self.keyed_value(project, trace, value, facet, decision)?;
let after = read(value, which)?;
let explicit = self
.decisions
.get(&FacetSelector::Order(which))
.is_some_and(|d| *d != SemanticDecision::KeepTarget);
if decision != SemanticDecision::TakeSource || explicit || after.len() <= before.len() {
return Ok(());
}
let (source_key, target_key) = if self.direction == TransitionDirection::OaToSa {
(keys.oa, keys.sa)
} else {
(keys.sa, keys.oa)
};
let (Some(source_key), Some(target_key)) = (source_key, target_key) else {
return Ok(());
};
let fact = capture_facet(project, trace.oa, trace.sa, &FacetSelector::Order(which))?;
let source: Vec<Id> = serde_json::from_value(
scalar::value(&fact, self.direction.source_layer())
.ok_or("Source order is unavailable.")?,
)
.map_err(|e| e.to_string())?;
let position = source
.iter()
.position(|id| *id == source_key)
.ok_or("Source member is absent.")?;
let map = self.order_reference_map()?;
let anchor = |id: &Id| {
map.get(id)
.and_then(|mapped| before.iter().position(|id| id == mapped))
};
let left = source[..position].iter().rev().find_map(anchor);
let right = source[position + 1..].iter().find_map(anchor);
let at = match (left, right) {
(Some(a), Some(b)) if a + 1 == b => Some(b),
(Some(a), None) if a + 1 == before.len() => Some(a + 1),
(None, Some(0)) => Some(0),
(None, None) if before.is_empty() => Some(0),
_ => None,
};
if let Some(at) = at {
let mut ordered = before;
ordered.insert(at, target_key);
write(value, which, ordered)
} else if form_context {
// An uncommitted membership list lets the user author a final order.
// The actual request still rejects ambiguous placement until explicitly decided.
Ok(())
} else {
Err("Ordered member insertion has no unique unchanged anchor; select an explicit final Order in Properties.".into())
}
}
}
@@ -1,4 +1,9 @@
//! Literal source search and line navigation, independent of accepted model state.
mod controller;
pub mod interaction;
pub mod query;
pub mod symbols;
pub use controller::*;
use iced::widget::text_editor::{Cursor, Position};
#[derive(Debug, Clone)]
@@ -0,0 +1,125 @@
//! Ephemeral editor navigation; no model commands or filesystem operations.
use super::query;
use iced::widget::text_editor::{Cursor, Position};
use oa_core::Id;
use std::sync::Arc;
use std::sync::atomic::AtomicU64;
#[derive(Debug, Clone)]
pub enum SymbolEvent {
Query(query::Action),
Back,
Close,
Choose {
stamp: query::QueryStamp,
reference: bool,
index: usize,
},
}
/// Identity of the mounted source view that emitted an action. Message queues
/// may outlive that view; request-time stamping alone cannot detect replay.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SymbolContext {
pub session: Id,
pub path: String,
}
#[derive(Debug, Clone)]
pub struct HistoryEntry {
pub session: Id,
pub path: String,
pub generation: u64,
pub cursor: Cursor,
}
#[derive(Debug, Clone)]
pub struct Request {
pub job: Id,
pub interaction: Id,
pub raw_interaction: u64,
pub stamp: query::QueryStamp,
pub path: String,
pub offset: usize,
pub cursor: Cursor,
pub action: query::Action,
}
#[derive(Debug, Clone)]
pub struct Completion {
pub request: Request,
pub result: Result<(Arc<query::Snapshot>, Arc<query::Results>), String>,
}
pub struct Reveal {
pub ticket: Id,
pub interaction: Id,
pub raw_interaction: u64,
pub snapshot: query::SnapshotKey,
pub path: String,
}
pub struct SymbolState {
pub open: bool,
pub interaction: Id,
pub raw_interaction: Arc<AtomicU64>,
pub serial: u64,
pub in_flight: Option<Id>,
pub request: Option<Request>,
pub cache: Option<Arc<query::Snapshot>>,
pub results: Option<Arc<query::Results>>,
pub notice: Option<String>,
pub back: Vec<HistoryEntry>,
pub reveal: Option<Reveal>,
}
impl Default for SymbolState {
fn default() -> Self {
Self {
open: false,
interaction: Id::new_v4(),
raw_interaction: Arc::new(AtomicU64::new(0)),
serial: 0,
in_flight: None,
request: None,
cache: None,
results: None,
notice: None,
back: Vec::new(),
reveal: None,
}
}
}
/// Iced uses zero-based UTF-8 byte columns. Reject stale or split-codepoint
/// coordinates; do not normalize CRLF or silently clamp query destinations.
pub fn byte_offset(text: &str, position: Position) -> Option<usize> {
let start = if position.line == 0 {
0
} else {
text.match_indices('\n').nth(position.line - 1)?.0 + 1
};
let end = text[start..]
.find('\n')
.map_or(text.len(), |end| start + end);
let offset = start.checked_add(position.column)?;
(offset <= end && text.is_char_boundary(offset)).then_some(offset)
}
pub fn cursor_offset(text: &str, cursor: Cursor) -> Option<usize> {
let position = cursor.selection.map_or(cursor.position, |selection| {
if (selection.line, selection.column) < (cursor.position.line, cursor.position.column) {
selection
} else {
cursor.position
}
});
byte_offset(text, position)
}
pub fn exact_cursor(text: &str, cursor: Cursor) -> bool {
byte_offset(text, cursor.position).is_some()
&& cursor
.selection
.is_none_or(|position| byte_offset(text, position).is_some())
}
@@ -0,0 +1,284 @@
//! Raw input invalidation and focus checks at widget-operation execution time.
use iced::advanced::{Clipboard, Layout, Shell, Widget, layout, overlay, renderer, widget};
use iced::{Element, Event, Length, Rectangle, Size, Task, Vector, keyboard, mouse, touch};
use std::sync::{
Arc,
atomic::{AtomicU64, Ordering},
};
/// Exhaustion fails closed: a saturated clock can never authorize navigation.
/// Replace the clock with a new workspace/controller, rather than wrapping it.
pub fn is_current(clock: &AtomicU64, expected: u64) -> bool {
expected != u64::MAX && clock.load(Ordering::Acquire) == expected
}
fn invalidate(clock: &AtomicU64, event: &Event) {
if matches!(
event,
Event::Keyboard(keyboard::Event::KeyPressed { .. })
| Event::Mouse(mouse::Event::ButtonPressed(_) | mouse::Event::WheelScrolled { .. })
| Event::Touch(touch::Event::FingerPressed { .. })
| Event::Window(iced::window::Event::Unfocused)
) {
let _ = clock.fetch_update(Ordering::AcqRel, Ordering::Acquire, |value| {
Some(value.saturating_add(1))
});
}
}
/// Transparent, including overlays: invalidate before the child can capture input.
pub fn observe<'a, Message: 'a, Theme: 'a, Renderer: renderer::Renderer + 'a>(
content: Element<'a, Message, Theme, Renderer>,
clock: Arc<AtomicU64>,
) -> Element<'a, Message, Theme, Renderer> {
Element::new(Observed { content, clock })
}
struct Observed<'a, Message, Theme, Renderer> {
content: Element<'a, Message, Theme, Renderer>,
clock: Arc<AtomicU64>,
}
impl<Message, Theme, Renderer: renderer::Renderer> Widget<Message, Theme, Renderer>
for Observed<'_, Message, Theme, Renderer>
{
fn size(&self) -> Size<Length> {
self.content.as_widget().size()
}
fn size_hint(&self) -> Size<Length> {
self.content.as_widget().size_hint()
}
fn tag(&self) -> widget::tree::Tag {
self.content.as_widget().tag()
}
fn state(&self) -> widget::tree::State {
self.content.as_widget().state()
}
fn children(&self) -> Vec<widget::Tree> {
self.content.as_widget().children()
}
fn diff(&self, tree: &mut widget::Tree) {
self.content.as_widget().diff(tree);
}
fn layout(
&mut self,
tree: &mut widget::Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
self.content.as_widget_mut().layout(tree, renderer, limits)
}
fn draw(
&self,
tree: &widget::Tree,
renderer: &mut Renderer,
theme: &Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
) {
self.content
.as_widget()
.draw(tree, renderer, theme, style, layout, cursor, viewport);
}
fn operate(
&mut self,
tree: &mut widget::Tree,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation,
) {
self.content
.as_widget_mut()
.operate(tree, layout, renderer, operation);
}
fn update(
&mut self,
tree: &mut widget::Tree,
event: &Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
viewport: &Rectangle,
) {
invalidate(&self.clock, event);
self.content.as_widget_mut().update(
tree, event, layout, cursor, renderer, clipboard, shell, viewport,
);
}
fn mouse_interaction(
&self,
tree: &widget::Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.content
.as_widget()
.mouse_interaction(tree, layout, cursor, viewport, renderer)
}
fn overlay<'a>(
&'a mut self,
tree: &'a mut widget::Tree,
layout: Layout<'a>,
renderer: &Renderer,
viewport: &Rectangle,
translation: Vector,
) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {
let clock = self.clock.clone();
self.content
.as_widget_mut()
.overlay(tree, layout, renderer, viewport, translation)
.map(|content| overlay::Element::new(Box::new(ObservedOverlay { content, clock })))
}
}
struct ObservedOverlay<'a, Message, Theme, Renderer> {
content: overlay::Element<'a, Message, Theme, Renderer>,
clock: Arc<AtomicU64>,
}
impl<Message, Theme, Renderer: renderer::Renderer> overlay::Overlay<Message, Theme, Renderer>
for ObservedOverlay<'_, Message, Theme, Renderer>
{
fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
self.content.as_overlay_mut().layout(renderer, bounds)
}
fn draw(
&self,
renderer: &mut Renderer,
theme: &Theme,
style: &renderer::Style,
layout: Layout<'_>,
cursor: mouse::Cursor,
) {
self.content
.as_overlay()
.draw(renderer, theme, style, layout, cursor);
}
fn operate(
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
operation: &mut dyn widget::Operation,
) {
self.content
.as_overlay_mut()
.operate(layout, renderer, operation);
}
fn update(
&mut self,
event: &Event,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) {
invalidate(&self.clock, event);
self.content
.as_overlay_mut()
.update(event, layout, cursor, renderer, clipboard, shell);
}
fn mouse_interaction(
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
renderer: &Renderer,
) -> mouse::Interaction {
self.content
.as_overlay()
.mouse_interaction(layout, cursor, renderer)
}
fn overlay<'a>(
&'a mut self,
layout: Layout<'a>,
renderer: &Renderer,
) -> Option<overlay::Element<'a, Message, Theme, Renderer>> {
let clock = self.clock.clone();
self.content
.as_overlay_mut()
.overlay(layout, renderer)
.map(|content| overlay::Element::new(Box::new(ObservedOverlay { content, clock })))
}
fn index(&self) -> f32 {
self.content.as_overlay().index()
}
}
/// Inspect all focus owners, then focus only the mounted target. Iced executes
/// Operation::Chain synchronously, without an intervening input event. Both
/// traversals recheck the raw clock; no result message authorizes later focus.
pub fn guarded_focus<Message: Send + 'static>(
target: widget::Id,
clock: Arc<AtomicU64>,
expected: u64,
) -> Task<Message> {
widget::operate(GuardedFocus::new(target, clock, expected))
}
struct GuardedFocus {
target: widget::Id,
clock: Arc<AtomicU64>,
expected: u64,
target_count: usize,
foreign_focus: bool,
apply: bool,
}
impl GuardedFocus {
fn new(target: widget::Id, clock: Arc<AtomicU64>, expected: u64) -> Self {
Self {
target,
clock,
expected,
target_count: 0,
foreign_focus: false,
apply: false,
}
}
}
impl<Message: 'static> widget::Operation<Message> for GuardedFocus {
fn traverse(&mut self, visit: &mut dyn FnMut(&mut dyn widget::Operation<Message>)) {
if is_current(&self.clock, self.expected) {
visit(self);
}
}
fn focusable(
&mut self,
id: Option<&widget::Id>,
_: Rectangle,
state: &mut dyn widget::operation::Focusable,
) {
if !is_current(&self.clock, self.expected) {
return;
}
if id == Some(&self.target) {
self.target_count += 1;
if self.apply {
state.focus();
}
} else if state.is_focused() {
self.foreign_focus = true;
}
}
fn finish(&self) -> widget::operation::Outcome<Message> {
if !self.apply
&& self.target_count == 1
&& !self.foreign_focus
&& is_current(&self.clock, self.expected)
{
widget::operation::Outcome::Chain(Box::new(Self {
apply: true,
..Self::new(self.target.clone(), self.clock.clone(), self.expected)
}))
} else {
widget::operation::Outcome::None
}
}
}
#[cfg(all(test, debug_assertions))]
mod tests;
@@ -0,0 +1,190 @@
use super::*;
use iced::advanced::widget::operation::{Focusable, Outcome};
use iced::widget::{column, text_input};
use iced::{Point, Theme};
#[derive(Default)]
struct FocusMap(Vec<(Option<widget::Id>, Rectangle, bool)>);
impl widget::Operation for FocusMap {
fn traverse(&mut self, visit: &mut dyn FnMut(&mut dyn widget::Operation)) {
visit(self);
}
fn focusable(&mut self, id: Option<&widget::Id>, bounds: Rectangle, state: &mut dyn Focusable) {
self.0.push((id.cloned(), bounds, state.is_focused()));
}
}
struct Mounted {
element: Element<'static, (), Theme, ()>,
tree: widget::Tree,
node: layout::Node,
}
impl Mounted {
fn new(clock: Arc<AtomicU64>) -> Self {
let content = column![
text_input("Editor", "source")
.id("editor")
.on_input(|_| ())
.padding(12),
text_input("Find", "")
.id("find")
.on_input(|_| ())
.padding(12),
]
.spacing(10)
.into();
let mut element = observe(content, clock);
let mut tree = widget::Tree::new(element.as_widget());
let node = element.as_widget_mut().layout(
&mut tree,
&(),
&layout::Limits::new(Size::ZERO, Size::new(400., 200.)),
);
Self {
element,
tree,
node,
}
}
fn pass(&mut self, operation: &mut dyn widget::Operation) {
self.element.as_widget_mut().operate(
&mut self.tree,
Layout::new(&self.node),
&(),
operation,
);
}
fn run(&mut self, operation: impl widget::Operation + 'static) {
let mut next: Box<dyn widget::Operation> = Box::new(operation);
loop {
self.pass(next.as_mut());
match next.finish() {
Outcome::Chain(chained) => next = chained,
Outcome::None => break,
Outcome::Some(()) => panic!("focus must not publish an application message"),
}
}
}
fn focus(&mut self) -> FocusMap {
let mut focus = FocusMap::default();
self.pass(&mut focus);
focus
}
fn click(&mut self, id: &str) {
let bounds = self
.focus()
.0
.into_iter()
.find(|(found, _, _)| found.as_ref() == Some(&widget::Id::from(id.to_owned())))
.unwrap()
.1;
let mut messages = Vec::new();
let mut shell = Shell::new(&mut messages);
self.element.as_widget_mut().update(
&mut self.tree,
&Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),
Layout::new(&self.node),
mouse::Cursor::Available(bounds.center()),
&(),
&mut iced::advanced::clipboard::Null,
&mut shell,
&Rectangle::with_size(Size::new(400., 200.)),
);
assert!(shell.is_event_captured());
assert!(
messages.is_empty(),
"focus-only click must not rely on App messages"
);
}
fn focused(&mut self, id: &str) -> bool {
self.focus()
.0
.into_iter()
.find(|(found, _, _)| found.as_ref() == Some(&widget::Id::from(id.to_owned())))
.unwrap()
.2
}
}
#[test]
fn captured_find_click_invalidates_without_app_message_and_preserves_focus() {
let clock = Arc::new(AtomicU64::new(0));
let mut ui = Mounted::new(clock.clone());
ui.run(GuardedFocus::new("editor".into(), clock.clone(), 0));
assert!(ui.focused("editor"));
ui.click("find");
assert!(!is_current(&clock, 0));
assert!(ui.focused("find"));
ui.run(GuardedFocus::new("editor".into(), clock.clone(), 0));
assert!(ui.focused("find"));
// Even a matching clock cannot authorize stealing another widget's focus.
ui.run(GuardedFocus::new(
"editor".into(),
clock.clone(),
clock.load(Ordering::Acquire),
));
assert!(ui.focused("find"));
assert!(!ui.focused("editor"));
}
#[test]
fn focus_rechecks_clock_between_inspection_and_application_and_missing_target_is_inert() {
let clock = Arc::new(AtomicU64::new(0));
let mut ui = Mounted::new(clock.clone());
let mut operation = GuardedFocus::new("editor".into(), clock.clone(), 0);
ui.pass(&mut operation);
let Outcome::Chain(mut apply) = <GuardedFocus as widget::Operation<()>>::finish(&operation)
else {
panic!("mounted, unopposed target must be eligible");
};
clock.store(1, Ordering::Release);
ui.pass(apply.as_mut());
assert!(!ui.focused("editor"));
ui.run(GuardedFocus::new("editor".into(), clock.clone(), 1));
assert!(ui.focused("editor"));
ui.run(GuardedFocus::new("removed-editor".into(), clock, 1));
assert!(ui.focused("editor"));
}
#[test]
fn raw_navigation_inputs_advance_but_passive_geometry_does_not_and_exhaustion_refuses() {
let clock = AtomicU64::new(0);
let events = [
Event::Keyboard(keyboard::Event::KeyPressed {
key: keyboard::Key::Named(keyboard::key::Named::ArrowLeft),
modified_key: keyboard::Key::Named(keyboard::key::Named::ArrowLeft),
physical_key: keyboard::key::Physical::Code(keyboard::key::Code::ArrowLeft),
location: keyboard::Location::Standard,
modifiers: keyboard::Modifiers::empty(),
text: None,
repeat: false,
}),
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),
Event::Mouse(mouse::Event::WheelScrolled {
delta: mouse::ScrollDelta::Lines { x: 0., y: 1. },
}),
Event::Touch(touch::Event::FingerPressed {
id: touch::Finger(1),
position: Point::ORIGIN,
}),
Event::Window(iced::window::Event::Unfocused),
];
for (index, event) in events.iter().enumerate() {
invalidate(&clock, event);
assert_eq!(clock.load(Ordering::Acquire), index as u64 + 1);
}
invalidate(
&clock,
&Event::Mouse(mouse::Event::CursorMoved {
position: Point::ORIGIN,
}),
);
invalidate(&clock, &Event::Window(iced::window::Event::Focused));
assert!(is_current(&clock, 5));
clock.store(u64::MAX - 1, Ordering::Release);
invalidate(&clock, &events[0]);
assert!(!is_current(&clock, u64::MAX));
invalidate(&clock, &events[0]);
assert_eq!(clock.load(Ordering::Acquire), u64::MAX);
assert!(!is_current(&clock, 0));
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
//! Pure preview and exact origin mapping for the guarded alias-rename controller.
pub mod origin;
pub mod preview;
@@ -0,0 +1,278 @@
//! Map a role-proven alias occurrence through the exact prepared source change.
//! This is cursor restoration, not target resolution or commit authority.
use oa_core::language::{self, Outline, OutlineLimits, Span, TokenClass};
use std::fmt;
const LIMITS: OutlineLimits = OutlineLimits {
max_source_bytes: 64 * 1024 * 1024,
max_tokens: 1_000_000,
max_declarations: 250_000,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OriginError {
Budget,
InvalidSource,
MissingOrigin,
ChangedStructure,
}
impl fmt::Display for OriginError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Budget => "The alias cursor preview exceeds its source scan budget. No rename was applied.",
Self::InvalidSource => "The alias cursor could not be verified in this source. No rename was applied.",
Self::MissingOrigin => "The original alias occurrence no longer matches. Preview again; no rename was applied.",
Self::ChangedStructure => "The preview changed source outside the expected alias tokens. No rename was applied.",
})
}
}
impl std::error::Error for OriginError {}
fn word(class: TokenClass) -> bool {
matches!(class, TokenClass::Identifier | TokenClass::Keyword)
}
/// The controller passes the exact alias span returned by the admitted symbol
/// hit. `marker` is Some only for a reference (its separate @ span), including
/// invocation with the caret on @. A declaration passes None.
pub fn map(
before: &str,
after: &str,
old_alias: &str,
new_alias: &str,
origin: Span,
marker: Option<Span>,
) -> Result<Span, OriginError> {
let old = language::outline(before, LIMITS).map_err(|_| OriginError::Budget)?;
let new = language::outline(after, LIMITS).map_err(|_| OriginError::Budget)?;
if old.has_lexical_errors || new.has_lexical_errors {
return Err(OriginError::InvalidSource);
}
if old.tokens.len() != new.tokens.len() {
return Err(OriginError::ChangedStructure);
}
let roles_before = roles(&old);
let roles_after = roles(&new);
let mut mapped = None;
for (index, (a, b)) in old.tokens.iter().zip(&new.tokens).enumerate() {
let left = &before[a.span.start..a.span.end];
let right = &after[b.span.start..b.span.end];
let alias_pair = word(a.class)
&& word(b.class)
&& left == old_alias
&& right == new_alias
&& roles_before[index].is_some()
&& roles_after[index].is_some()
&& roles_before[index].map(|role| role.is_some())
== roles_after[index].map(|role| role.is_some());
if a.span == origin {
if !alias_pair || roles_before[index] != Some(marker) {
return Err(OriginError::MissingOrigin);
}
mapped = Some(b.span);
}
if !alias_pair && (left != right || a.class != b.class) {
return Err(OriginError::ChangedStructure);
}
}
mapped.ok_or(OriginError::MissingOrigin)
}
/// Outer None is not an alias role; Some(None) is a declaration alias;
/// Some(Some(span)) is a live @ reference with its exact separate marker.
/// Scan sorted declaration spans and tokens together, without repeated searches.
fn roles(outline: &Outline<'_>) -> Vec<Option<Option<Span>>> {
let mut result = vec![None; outline.tokens.len()];
let mut declarations = outline.declarations.iter().peekable();
let mut significant = None;
for (index, token) in outline.tokens.iter().enumerate() {
while declarations
.peek()
.is_some_and(|d| d.alias_span.start < token.span.start)
{
declarations.next();
}
if word(token.class) {
if declarations
.peek()
.is_some_and(|d| d.alias_span == token.span)
{
result[index] = Some(None);
} else if let Some(previous) = significant {
let span: Span = previous;
if &outline.source[span.start..span.end] == "@" {
result[index] = Some(Some(span));
}
}
}
if !matches!(token.class, TokenClass::Whitespace | TokenClass::Comment) {
significant = Some(token.span);
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
fn occurrence(source: &str, needle: &str, which: usize) -> Span {
let start = source.match_indices(needle).nth(which).unwrap().0;
Span {
start,
end: start + needle.len(),
}
}
#[test]
fn maps_last_repeated_reference_with_unicode_crlf_and_comment_separator() {
let before =
"oa_activity a \"救援\" {}\r\n// @a is prose\r\nsource @a; target @ // a\r\n a;\r\n";
let after = "oa_activity renamed \"救援\" {}\r\n// @a is prose\r\nsource @renamed; target @ // a\r\n renamed;\r\n";
let start = before.rfind(" a;").unwrap() + 1;
let marker = before.rfind("@ //").unwrap();
let mapped = map(
before,
after,
"a",
"renamed",
Span {
start,
end: start + 1,
},
Some(Span {
start: marker,
end: marker + 1,
}),
)
.unwrap();
assert_eq!(&after[mapped.start..mapped.end], "renamed");
assert_eq!(mapped.start, after.rfind(" renamed;").unwrap() + 1);
assert_eq!(
before[..start].bytes().filter(|b| *b == b'\n').count(),
after[..mapped.start]
.bytes()
.filter(|b| *b == b'\n')
.count()
);
}
#[test]
fn preserves_final_same_line_occurrence_not_first_or_prose() {
let before = "oa_activity a \"a @a\" {} source @a; target @a;";
let after = "oa_activity longer \"a @a\" {} source @longer; target @longer;";
let start = before.rfind("@a").unwrap();
let result = map(
before,
after,
"a",
"longer",
Span {
start: start + 1,
end: start + 2,
},
Some(Span {
start,
end: start + 1,
}),
)
.unwrap();
assert_eq!(result.start, after.rfind("@longer").unwrap() + 1);
let prose = occurrence(before, "a @a", 0);
assert!(
map(
before,
after,
"a",
"longer",
Span {
start: prose.start,
end: prose.start + 1
},
None
)
.is_err()
);
}
#[test]
fn permits_identifier_keyword_transitions_in_alias_roles() {
let before = "oa_activity a \"Name\" {} source @a;";
let alias = occurrence(before, "a \"Name", 0);
let origin = Span {
start: alias.start,
end: alias.start + 1,
};
for replacement in ["none", "include", "oa_activity"] {
assert!(oa_core::valid_alias(replacement));
assert_eq!(
language::tokenize(replacement)[0].class,
TokenClass::Keyword
);
let after = format!("oa_activity {replacement} \"Name\" {{}} source @{replacement};");
let mapped = map(before, &after, "a", replacement, origin, None).unwrap();
assert_eq!(&after[mapped.start..mapped.end], replacement);
assert_eq!(
map(&after, before, replacement, "a", mapped, None).unwrap(),
origin
);
}
}
#[test]
fn rejects_changed_trivia_non_alias_words_and_wrong_marker() {
let before = "oa_activity a \"Name\" {} source @a;";
let after = "oa_activity b \"Name\" {} source @b;";
let start = before.rfind("@a").unwrap();
let span = Span {
start: start + 1,
end: start + 2,
};
let marker = Some(Span {
start,
end: start + 1,
});
assert_eq!(
map(
before,
&after.replace("Name", "Other"),
"a",
"b",
span,
marker
),
Err(OriginError::ChangedStructure)
);
assert_eq!(
map(
before,
&after.replace(" source", " source"),
"a",
"b",
span,
marker
),
Err(OriginError::ChangedStructure)
);
assert_eq!(
map(before, after, "a", "b", span, None),
Err(OriginError::MissingOrigin)
);
assert!(
map(
before,
after,
"a",
"b",
Span {
start: 0,
end: usize::MAX
},
marker
)
.is_err()
);
}
}
@@ -0,0 +1,578 @@
//! Complete, bounded line-ordinal previews of an already prepared alias rename.
//!
//! Source text remains in the caller's immutable before/after snapshots. This
//! module owns only paths and indexes; it is not rename or commit authority.
use oa_core::source_project::SourceBundle;
use std::{fmt, ops::Range};
const CONTEXT: usize = 3;
// A byte-grid boundary can move back by at most three UTF-8 continuation bytes,
// so a 252-byte grid yields fragments of at most 255 bytes, independent of input.
const SEGMENT_GRID: usize = 252;
/// Count all bounded fragments of exact source text; an empty line has one
/// empty fragment. Page these as well as lines, never mount an unbounded line.
pub fn segment_count(text: &str) -> usize {
text.len().div_ceil(SEGMENT_GRID).max(1)
}
/// Constant-time UTF-8-safe page lookup. Concatenating every fragment gives the
/// original bytes, including CRLF. No ellipsis or truncation replaces content.
pub fn text_segment(text: &str, index: usize) -> Option<&str> {
if index >= segment_count(text) {
return None;
}
let mut start = index.checked_mul(SEGMENT_GRID)?;
let mut end = start.saturating_add(SEGMENT_GRID).min(text.len());
while !text.is_char_boundary(start) {
start -= 1;
}
while !text.is_char_boundary(end) {
end -= 1;
}
text.get(start..end)
}
const LIMITS: Limits = Limits {
files: 256,
changed_lines: 50_000,
display_bytes: 8 * 1024 * 1024,
};
#[derive(Clone, Copy)]
struct Limits {
files: usize,
changed_lines: usize,
display_bytes: usize,
}
#[derive(Debug)]
pub struct Preview {
files: Vec<File>,
changed_lines: usize,
display_bytes: usize,
}
#[derive(Debug)]
pub struct File {
path: String,
hunks: Vec<Hunk>,
}
#[derive(Debug)]
pub struct Hunk {
lines: Vec<Line>,
}
#[derive(Debug)]
pub struct Line {
number: usize,
before: Range<usize>,
after: Range<usize>,
changed: bool,
}
#[derive(Debug, PartialEq, Eq)]
pub enum PreviewError {
MembershipChanged,
LineCountChanged(String),
LineEndingChanged { path: String, line: usize },
TooManyFiles { limit: usize },
TooManyChangedLines { limit: usize },
TooManyDisplayBytes { limit: usize },
}
impl fmt::Display for PreviewError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MembershipChanged => write!(
f,
"Rename preview refused: the entry or source file membership changed. No rename was applied."
),
Self::LineCountChanged(path) => write!(
f,
"Rename preview refused: the line count changed in {path}. No rename was applied."
),
Self::LineEndingChanged { path, line } => write!(
f,
"Rename preview refused: the line ending changed in {path}:{line}. No rename was applied."
),
Self::TooManyFiles { limit } => write!(
f,
"Rename preview exceeds {limit} changed files. A complete preview is required; no rename was applied."
),
Self::TooManyChangedLines { limit } => write!(
f,
"Rename preview exceeds {limit} changed source lines. A complete preview is required; no rename was applied."
),
Self::TooManyDisplayBytes { limit } => write!(
f,
"Rename preview exceeds {limit} display bytes (paths and both versions of changed/context lines). A complete preview is required; no rename was applied."
),
}
}
}
impl std::error::Error for PreviewError {}
impl Preview {
pub fn build(before: &SourceBundle, after: &SourceBundle) -> Result<Self, PreviewError> {
Self::with_limits(before, after, LIMITS)
}
fn with_limits(
before: &SourceBundle,
after: &SourceBundle,
limits: Limits,
) -> Result<Self, PreviewError> {
if before.entry != after.entry
|| !before.files.contains_key(&before.entry)
|| !before.files.keys().eq(after.files.keys())
{
return Err(PreviewError::MembershipChanged);
}
let mut preview = Self {
files: Vec::new(),
changed_lines: 0,
display_bytes: 0,
};
for ((path, old), (_, new)) in before.files.iter().zip(&after.files) {
if old == new {
continue;
}
if preview.files.len() == limits.files {
return Err(PreviewError::TooManyFiles {
limit: limits.files,
});
}
// A changed source line can contain arbitrarily many renamed tokens.
// Count the line once; this count is never a semantic-reference count.
let mut changed = Vec::new();
let mut old_lines = Lines::new(old);
let mut new_lines = Lines::new(new);
let mut count = 0;
loop {
match (old_lines.next(), new_lines.next()) {
(None, None) => break,
(Some(a), Some(b)) => {
count += 1;
if old[a.content_end..a.end] != new[b.content_end..b.end] {
return Err(PreviewError::LineEndingChanged {
path: path.clone(),
line: count,
});
}
if old[a.start..a.end] != new[b.start..b.end] {
if preview.changed_lines == limits.changed_lines {
return Err(PreviewError::TooManyChangedLines {
limit: limits.changed_lines,
});
}
preview.changed_lines += 1;
changed.push(count - 1);
}
}
_ => return Err(PreviewError::LineCountChanged(path.clone())),
}
}
// Merge touching context intervals in order, without pairwise diff.
// At most 7 indexed lines per changed line are retained; unchanged
// lines outside these intervals are scanned but never indexed.
let mut ranges: Vec<Range<usize>> = Vec::new();
for line in changed {
let range =
line.saturating_sub(CONTEXT)..line.saturating_add(CONTEXT + 1).min(count);
if let Some(previous) = ranges.last_mut()
&& range.start <= previous.end
{
previous.end = previous.end.max(range.end);
continue;
}
ranges.push(range);
}
preview.charge(path.len(), limits)?;
let mut file = File {
path: path.clone(),
hunks: Vec::new(),
};
let mut pairs = Lines::new(old).zip(Lines::new(new)).enumerate();
for range in ranges {
let mut hunk = Hunk { lines: Vec::new() };
for (ordinal, (a, b)) in pairs.by_ref() {
if ordinal < range.start {
continue;
}
// Charge exact UTF-8 bytes, including preserved endings and
// both copies of shared context, before adding the index.
// No render-time omission or shortening grants admission.
preview.charge(a.end - a.start, limits)?;
preview.charge(b.end - b.start, limits)?;
hunk.lines.push(Line {
number: ordinal + 1,
changed: old[a.start..a.end] != new[b.start..b.end],
before: a.start..a.end,
after: b.start..b.end,
});
if ordinal + 1 == range.end {
break;
}
}
file.hunks.push(hunk);
}
preview.files.push(file);
}
Ok(preview)
}
fn charge(&mut self, bytes: usize, limits: Limits) -> Result<(), PreviewError> {
let Some(total) = self.display_bytes.checked_add(bytes) else {
return Err(PreviewError::TooManyDisplayBytes {
limit: limits.display_bytes,
});
};
if total > limits.display_bytes {
return Err(PreviewError::TooManyDisplayBytes {
limit: limits.display_bytes,
});
}
self.display_bytes = total;
Ok(())
}
/// All admitted files in source path order; suitable for a file picker/search.
pub fn files(&self) -> &[File] {
&self.files
}
/// Changed source lines, not occurrences, declarations or semantic uses.
pub fn changed_line_count(&self) -> usize {
self.changed_lines
}
/// Exact displayed source bytes for both sides plus each stored path once.
/// Index metadata is separately bounded by 7 lines per changed line.
pub fn display_bytes(&self) -> usize {
self.display_bytes
}
#[cfg(test)]
pub fn is_empty(&self) -> bool {
self.files.is_empty()
}
}
impl File {
pub fn path(&self) -> &str {
&self.path
}
/// Every hunk is present; the caller may page these indexes, never truncate.
pub fn hunks(&self) -> &[Hunk] {
&self.hunks
}
}
impl Hunk {
/// The complete ordered line slice supports paging even a large single hunk.
pub fn lines(&self) -> &[Line] {
&self.lines
}
}
impl Line {
/// One-based source line number, identical on both sides.
pub fn number(&self) -> usize {
self.number
}
pub fn changed(&self) -> bool {
self.changed
}
/// Borrow from the immutable original file; includes its exact line ending.
pub fn before_text<'a>(&self, original: &'a str) -> Option<&'a str> {
original.get(self.before.clone())
}
/// Borrow from the immutable candidate file; includes its exact line ending.
pub fn after_text<'a>(&self, candidate: &'a str) -> Option<&'a str> {
candidate.get(self.after.clone())
}
}
struct RawLine {
start: usize,
content_end: usize,
end: usize,
}
struct Lines<'a> {
bytes: &'a [u8],
offset: usize,
}
impl<'a> Lines<'a> {
fn new(text: &'a str) -> Self {
Self {
bytes: text.as_bytes(),
offset: 0,
}
}
}
impl Iterator for Lines<'_> {
type Item = RawLine;
fn next(&mut self) -> Option<Self::Item> {
if self.offset == self.bytes.len() {
return None;
}
let start = self.offset;
// The compiler and source navigation count LF, not bare CR, as a line
// boundary. Preserve CRLF as an ending and bare CR as source content.
while self.offset < self.bytes.len() && self.bytes[self.offset] != b'\n' {
self.offset += 1;
}
let mut content_end = self.offset;
if self.offset < self.bytes.len() {
if self.offset > start && self.bytes[self.offset - 1] == b'\r' {
content_end -= 1;
}
self.offset += 1;
}
Some(RawLine {
start,
content_end,
end: self.offset,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
fn bundle(source: &str) -> SourceBundle {
SourceBundle {
entry: "救援.arcadia".into(),
files: [("救援.arcadia".into(), source.into())].into(),
}
}
#[test]
fn long_unicode_lines_are_fully_reachable_as_bounded_fragments() {
let text = format!("{}救援🙂{}\r\n", "a".repeat(251), "🙂".repeat(200));
let pieces: Vec<_> = (0..segment_count(&text))
.map(|i| text_segment(&text, i).unwrap())
.collect();
assert!(pieces.len() > 2);
assert!(pieces.iter().all(|part| part.len() <= 255));
assert_eq!(pieces.concat(), text);
assert_eq!(text_segment(&text, segment_count(&text)), None);
assert_eq!(text_segment(&text, usize::MAX), None);
assert_eq!(segment_count(""), 1);
assert_eq!(text_segment("", 0), Some(""));
}
#[test]
fn preserves_unicode_mixed_endings_and_counts_lines_not_repeated_uses() {
let old = bundle("// 救援\r\n@a @a\ncontext\r@a");
let new = bundle("// 救援\r\n@long @long\ncontext\r@long");
let preview = Preview::build(&old, &new).unwrap();
assert_eq!(preview.changed_line_count(), 2);
let file = &preview.files()[0];
assert_eq!(file.path(), "救援.arcadia");
assert_eq!(file.hunks().len(), 1);
let lines = file.hunks()[0].lines();
assert_eq!(
lines.iter().map(Line::number).collect::<Vec<_>>(),
[1, 2, 3]
);
assert_eq!(
lines[0].before_text(&old.files[&old.entry]),
Some("// 救援\r\n")
);
assert_eq!(
lines[1].after_text(&new.files[&new.entry]),
Some("@long @long\n")
);
assert_eq!(
lines[2].after_text(&new.files[&new.entry]),
Some("context\r@long")
);
assert!(lines[1].changed() && lines[2].changed());
assert!(!lines[0].changed());
assert_eq!(
preview.display_bytes(),
old.entry.len() + old.files[&old.entry].len() + new.files[&new.entry].len()
);
}
#[test]
fn first_and_last_lines_form_complete_separate_hunks_and_pages() {
let old = bundle("a\n1\n2\n3\n4\n5\n6\n7\n8\n9\na");
let new = bundle("long\n1\n2\n3\n4\n5\n6\n7\n8\n9\nlong");
let preview = Preview::build(&old, &new).unwrap();
let hunks = preview.files()[0].hunks();
assert_eq!(hunks.len(), 2);
let page_numbers: Vec<_> = hunks
.iter()
.flat_map(|h| h.lines().chunks(2))
.flat_map(|page| page.iter().map(Line::number))
.collect();
assert_eq!(page_numbers, [1, 2, 3, 4, 8, 9, 10, 11]);
assert_eq!(
hunks[1].lines()[3].after_text(&new.files[&new.entry]),
Some("long")
);
}
#[test]
fn nearby_changes_merge_and_all_changed_files_are_reachable() {
let mut old = bundle("a\n1\n2\n3\n4\n5\na\n");
let mut new = bundle("b\n1\n2\n3\n4\n5\nb\n");
old.files.insert("other.arcadia".into(), "a a a".into());
new.files.insert("other.arcadia".into(), "b b b".into());
let preview = Preview::build(&old, &new).unwrap();
assert_eq!(preview.changed_line_count(), 3);
assert_eq!(preview.files().len(), 2);
assert_eq!(preview.files()[0].path(), "other.arcadia");
assert_eq!(preview.files()[0].hunks()[0].lines().len(), 1);
assert_eq!(preview.files()[1].hunks().len(), 1);
assert_eq!(preview.files()[1].hunks()[0].lines().len(), 7);
}
#[test]
fn unchanged_and_empty_sources_have_no_preview() {
for source in ["", "a\r\nb\n", "a"] {
let original = bundle(source);
let preview = Preview::build(&original, &original).unwrap();
assert!(preview.is_empty());
assert_eq!(preview.changed_line_count(), 0);
assert_eq!(preview.display_bytes(), 0);
}
}
#[test]
fn refuses_membership_entry_line_count_and_line_ending_changes() {
let old = bundle("a\nb");
let mut new = old.clone();
new.files.insert("extra.arcadia".into(), "".into());
assert_eq!(
Preview::build(&old, &new).unwrap_err(),
PreviewError::MembershipChanged
);
let mut new = old.clone();
new.entry = "missing.arcadia".into();
assert_eq!(
Preview::build(&old, &new).unwrap_err(),
PreviewError::MembershipChanged
);
assert!(matches!(
Preview::build(&old, &bundle("a\nb\nc")),
Err(PreviewError::LineEndingChanged { .. }) | Err(PreviewError::LineCountChanged(_))
));
assert!(matches!(
Preview::build(&bundle("a\nb\n"), &bundle("a\n")),
Err(PreviewError::LineCountChanged(_))
));
for (a, b) in [("a\r\n", "a\n"), ("a\r", "a\n"), ("a", "a\n")] {
assert_eq!(
Preview::build(&bundle(a), &bundle(b)).unwrap_err(),
PreviewError::LineEndingChanged {
path: old.entry.clone(),
line: 1
}
);
}
}
#[test]
fn each_bound_is_exact_and_overflow_never_returns_a_partial_preview() {
let old = bundle("a\ncontext\na");
let new = bundle("bbb\ncontext\nbbb");
let exact = old.entry.len() + old.files[&old.entry].len() + new.files[&new.entry].len();
let limits = Limits {
files: 1,
changed_lines: 2,
display_bytes: exact,
};
assert!(Preview::with_limits(&old, &new, limits).is_ok());
assert_eq!(
Preview::with_limits(&old, &new, Limits { files: 0, ..limits }).unwrap_err(),
PreviewError::TooManyFiles { limit: 0 }
);
assert_eq!(
Preview::with_limits(
&old,
&new,
Limits {
changed_lines: 1,
..limits
}
)
.unwrap_err(),
PreviewError::TooManyChangedLines { limit: 1 }
);
assert_eq!(
Preview::with_limits(
&old,
&new,
Limits {
display_bytes: exact - 1,
..limits
}
)
.unwrap_err(),
PreviewError::TooManyDisplayBytes { limit: exact - 1 }
);
let long = bundle(&"a".repeat(LIMITS.display_bytes));
assert!(matches!(
Preview::build(&bundle("b"), &long),
Err(PreviewError::TooManyDisplayBytes { .. })
));
}
#[test]
fn limits_apply_to_the_whole_preview_not_each_file() {
let mut old = bundle("a");
let mut new = bundle("b");
old.files.insert("second.arcadia".into(), "a".into());
new.files.insert("second.arcadia".into(), "b".into());
let limits = Limits {
files: 2,
changed_lines: 2,
display_bytes: old.entry.len() + "second.arcadia".len() + 4,
};
let complete = Preview::with_limits(&old, &new, limits).unwrap();
assert_eq!(complete.files().len(), 2);
assert_eq!(complete.changed_line_count(), 2);
assert_eq!(complete.display_bytes(), limits.display_bytes);
assert!(matches!(
Preview::with_limits(&old, &new, Limits { files: 1, ..limits }),
Err(PreviewError::TooManyFiles { limit: 1 })
));
assert!(matches!(
Preview::with_limits(
&old,
&new,
Limits {
changed_lines: 1,
..limits
}
),
Err(PreviewError::TooManyChangedLines { limit: 1 })
));
assert!(matches!(
Preview::with_limits(
&old,
&new,
Limits {
display_bytes: limits.display_bytes - 1,
..limits
}
),
Err(PreviewError::TooManyDisplayBytes { .. })
));
}
}
+217 -4
View File
@@ -1,7 +1,7 @@
//! Per-file drafts and navigation. Accepted model/source history lives in Document.
use iced::widget::text_editor::Cursor;
use oa_core::{
language,
Id, language,
source_project::{self, CompiledSourceProject, ProjectLimits, SourceBundle, SourceDiagnostic},
};
use std::collections::{BTreeMap, BTreeSet};
@@ -86,6 +86,7 @@ pub struct Buffer {
pub cursor: Cursor,
past: Vec<String>,
future: Vec<String>,
generation: u64,
}
impl Buffer {
@@ -99,14 +100,20 @@ impl Buffer {
},
past: Vec::new(),
future: Vec::new(),
generation: 0,
}
}
pub fn dirty(&self) -> bool {
self.text != self.baseline
}
pub fn generation(&self) -> u64 {
self.generation
}
}
pub struct Workspace {
session: Id,
revision: u64,
pub entry: String,
pub active: String,
pub files: BTreeMap<String, Buffer>,
@@ -117,6 +124,35 @@ pub struct Workspace {
}
impl Workspace {
/// Ephemeral editor identity, never a model identity or recovery payload.
pub fn session(&self) -> Id {
self.session
}
pub fn revision(&self) -> u64 {
self.revision
}
fn advance(&mut self) -> u64 {
if let Some(revision) = self.revision.checked_add(1) {
self.revision = revision;
} else {
self.reset_navigation_session();
}
self.revision
}
/// A changed filesystem root must not reuse queued navigation from Save As.
pub fn reset_navigation_session(&mut self) {
self.session = Id::new_v4();
self.revision = 0;
for buffer in self.files.values_mut() {
buffer.generation = 0;
}
}
pub fn set_reachable(&mut self, reachable: BTreeSet<String>) {
if self.reachable != reachable {
self.advance();
self.reachable = reachable;
}
}
pub fn recovery_snapshot(&self) -> RecoveryWorkspace {
RecoveryWorkspace {
entry: self.entry.clone(),
@@ -136,6 +172,8 @@ impl Workspace {
pub fn from_recovery(saved: RecoveryWorkspace) -> Result<Self, String> {
saved.validate()?;
Ok(Self {
session: Id::new_v4(),
revision: 0,
entry: saved.entry,
active: saved.active,
files: saved
@@ -154,6 +192,8 @@ impl Workspace {
}
pub fn new(bundle: &SourceBundle, applied: bool) -> Self {
Self {
session: Id::new_v4(),
revision: 0,
entry: bundle.entry.clone(),
active: bundle.entry.clone(),
files: bundle
@@ -191,11 +231,20 @@ impl Workspace {
}
}
pub fn edit(&mut self, text: String, cursor: Cursor) {
let changed = self.files.get(&self.active).is_none_or(|b| b.text != text);
let generation = if changed {
self.advance()
} else {
self.revision
};
let buffer = self
.files
.entry(self.active.clone())
.or_insert_with(|| Buffer::new(String::new()));
buffer.cursor = cursor;
if changed {
buffer.generation = generation;
}
if text != buffer.text {
buffer.past.push(std::mem::replace(&mut buffer.text, text));
if buffer.past.len() > 100 {
@@ -268,6 +317,8 @@ impl Workspace {
} else {
buffer.future.push(previous);
}
let generation = self.advance();
self.files.get_mut(&self.active).unwrap().generation = generation;
self.trim_history(DRAFT_HISTORY_BYTES);
true
}
@@ -281,6 +332,7 @@ impl Workspace {
}
}
pub fn accept(&mut self, bundle: &SourceBundle) {
let generation = self.advance();
if self.entry != bundle.entry
&& !bundle.files.contains_key(&self.entry)
&& self.files.get(&self.entry).is_some_and(|b| !b.dirty())
@@ -291,7 +343,13 @@ impl Workspace {
self.reachable = bundle.files.keys().cloned().collect();
for (path, text) in &bundle.files {
let cursor = self.files.get(path).map(|b| b.cursor);
let previous_generation = self
.files
.get(path)
.filter(|b| b.text == *text)
.map(|b| b.generation);
let mut buffer = Buffer::new(text.clone());
buffer.generation = previous_generation.unwrap_or(generation);
if let Some(cursor) = cursor {
buffer.cursor = cursor;
}
@@ -303,10 +361,22 @@ impl Workspace {
self.applied = true;
}
pub fn discovered(&mut self, bundle: &SourceBundle, reachable: BTreeSet<String>) {
let changed = self.reachable != reachable
|| bundle
.files
.keys()
.any(|path| !self.files.contains_key(path));
let generation = if changed {
self.advance()
} else {
self.revision
};
for (path, text) in &bundle.files {
self.files
.entry(path.clone())
.or_insert_with(|| Buffer::new(text.clone()));
self.files.entry(path.clone()).or_insert_with(|| {
let mut buffer = Buffer::new(text.clone());
buffer.generation = generation;
buffer
});
}
self.reachable = reachable;
}
@@ -314,6 +384,7 @@ impl Workspace {
if self.reachable.contains(path) || self.files.get(path).is_none_or(Buffer::dirty) {
return false;
}
self.advance();
self.files.remove(path);
if self.active == path {
self.active = self.entry.clone();
@@ -376,6 +447,148 @@ pub fn lint(bundle: &SourceBundle) -> Vec<SourceDiagnostic> {
mod tests {
use super::*;
use oa_core::Project;
#[test]
fn fresh_session_cannot_reuse_a_retained_buffer_generation() {
let bundle = SourceBundle {
entry: "main.arcadia".into(),
files: BTreeMap::from([
("main.arcadia".into(), "first".into()),
("other.arcadia".into(), "other".into()),
]),
};
let mut workspace = Workspace::new(&bundle, true);
let cursor = workspace.files["main.arcadia"].cursor;
workspace.edit("second".into(), cursor);
workspace.reset_navigation_session();
let before = workspace.files["main.arcadia"].generation();
workspace.edit("third".into(), cursor);
assert_ne!(workspace.files["main.arcadia"].generation(), before);
workspace.switch("other.arcadia", cursor);
workspace.revision = u64::MAX;
workspace.edit("changed other".into(), cursor);
let after_wrap = workspace.files["main.arcadia"].generation();
workspace.switch("main.arcadia", cursor);
workspace.edit("fourth".into(), cursor);
assert_ne!(workspace.files["main.arcadia"].generation(), after_wrap);
assert!(workspace.undo(false));
assert_eq!(workspace.text(), "third");
}
#[test]
fn navigation_versions_distinguish_reopened_recovered_and_changed_drafts() {
let bundle = SourceBundle {
entry: "project.arcadia".into(),
files: BTreeMap::from([
("project.arcadia".into(), "entry\r\n".into()),
("part.arcadia".into(), "雨 draft\r\n".into()),
]),
};
let mut workspace = Workspace::new(&bundle, true);
let reopened = Workspace::new(&bundle, true);
let recovered = Workspace::from_recovery(workspace.recovery_snapshot()).unwrap();
assert_ne!(workspace.session(), reopened.session());
assert_ne!(workspace.session(), recovered.session());
assert_eq!(workspace.bundle(), recovered.bundle());
let saved = serde_json::to_value(workspace.recovery_snapshot()).unwrap();
assert!(saved.get("session").is_none() && saved.get("revision").is_none());
let cursor = Cursor {
position: iced::widget::text_editor::Position { line: 0, column: 3 },
selection: None,
};
let revision = workspace.revision();
workspace.edit(workspace.text().into(), cursor);
assert_eq!(
workspace.revision(),
revision,
"selection is not a text change"
);
workspace.switch("part.arcadia", cursor);
assert_eq!(
workspace.revision(),
revision,
"switching retains the snapshot"
);
let untouched = workspace.files["project.arcadia"].generation();
workspace.edit("雨 unfinished !\r\n".into(), cursor);
let edited = workspace.files["part.arcadia"].generation();
assert!(workspace.revision() > revision);
assert_eq!(workspace.files["project.arcadia"].generation(), untouched);
assert!(workspace.undo(false));
assert_eq!(workspace.bundle(), bundle);
assert!(workspace.files["part.arcadia"].generation() > edited);
assert!(workspace.undo(true));
assert_eq!(workspace.text(), "雨 unfinished !\r\n");
let previous_session = workspace.session();
let previous_text = workspace.bundle();
workspace.reset_navigation_session();
assert_ne!(workspace.session(), previous_session);
assert_eq!(workspace.bundle(), previous_text);
assert!(
workspace.undo(false),
"session reset preserves text history"
);
}
#[test]
fn navigation_scope_changes_invalidate_without_changing_unchanged_positions() {
let bundle = SourceBundle {
entry: "project.arcadia".into(),
files: BTreeMap::from([
("project.arcadia".into(), "entry".into()),
("part.arcadia".into(), "part".into()),
]),
};
let mut workspace = Workspace::new(&bundle, true);
let entry_generation = workspace.files[&bundle.entry].generation();
let initial_revision = workspace.revision();
workspace.set_reachable(BTreeSet::from([bundle.entry.clone()]));
assert!(workspace.revision() > initial_revision);
let membership_revision = workspace.revision();
workspace.set_reachable(workspace.reachable.clone());
assert_eq!(workspace.revision(), membership_revision);
assert!(workspace.discard_detached("part.arcadia"));
assert!(workspace.revision() > membership_revision);
let closed_revision = workspace.revision();
workspace.discovered(&bundle, BTreeSet::from([bundle.entry.clone()]));
assert!(workspace.revision() > closed_revision);
assert_eq!(
workspace.files[&bundle.entry].generation(),
entry_generation
);
assert!(workspace.files["part.arcadia"].generation() > closed_revision);
let discovered_revision = workspace.revision();
workspace.discovered(&bundle, workspace.reachable.clone());
assert_eq!(workspace.revision(), discovered_revision);
workspace.accept(&bundle);
assert!(
workspace.revision() > discovered_revision,
"validation evidence changed"
);
assert_eq!(
workspace.files[&bundle.entry].generation(),
entry_generation
);
assert_eq!(workspace.bundle(), bundle);
}
#[test]
fn navigation_revision_wrap_cannot_reuse_an_old_workspace_key() {
let bundle = SourceBundle {
entry: "project.arcadia".into(),
files: BTreeMap::from([("project.arcadia".into(), "original".into())]),
};
let mut workspace = Workspace::new(&bundle, true);
workspace.revision = u64::MAX;
let before = workspace.session();
let cursor = workspace.files[&bundle.entry].cursor;
workspace.edit("changed".into(), cursor);
assert_ne!(workspace.session(), before);
assert_eq!(workspace.revision(), 0);
assert!(workspace.undo(false));
assert_eq!(workspace.bundle(), bundle);
}
#[test]
fn draft_history_budget_covers_inactive_files_without_discarding_drafts() {
let bundle = SourceBundle {
+4 -2
View File
@@ -377,7 +377,8 @@ fn source_navigation_waits_for_editor_layout_and_cancels_on_edit() {
send(&mut app, Message::SourceForSelection);
assert_eq!(app.page, Page::Text);
assert!(app.source_jump.is_some());
send(&mut app, Message::SourceViewport);
let ticket = app.source_reveal_ticket();
send(&mut app, Message::SourceViewport(ticket));
assert!(app.source_jump.is_none());
send(&mut app, Message::SourceForSelection);
assert!(app.source_jump.is_some());
@@ -409,7 +410,8 @@ fn source_find_navigates_an_invalid_draft_without_applying_or_losing_it() {
cursor.selection,
Some(text_editor::Position { line: 0, column: 9 })
);
send(&mut app, Message::SourceViewport);
let ticket = app.source_reveal_ticket();
send(&mut app, Message::SourceViewport(ticket));
assert_eq!(app.source_editor.cursor(), cursor);
send(
&mut app,
+522 -9
View File
@@ -1,3 +1,4 @@
mod source_symbols;
pub(crate) mod traceability;
use crate::{
app::{App, Choice, FileOperation, Message, Page, Pending},
@@ -349,6 +350,13 @@ pub fn view(app: &App) -> View<'_, Message> {
if app.pending.is_some() {
return modal(root,column![text("Keep your changes?").size(21),text("Save the model and pending edits before continuing. Invalid drafts stay available for correction.").size(13),row![action("Cancel",Message::Cancel),action("Discard changes",Message::Discard),button("Save & continue").padding(10).on_press(Message::SaveAndContinue)].spacing(8)].spacing(16).into());
}
if app.source_rename.open() {
return modal_width(
root,
crate::app::source_rename::dialog(app),
(app.window_size.width - 32.).clamp(120., 760.),
);
}
root
}
fn modal<'a>(base: View<'a, Message>, content: View<'a, Message>) -> View<'a, Message> {
@@ -1003,6 +1011,13 @@ fn source_files(app: &App) -> View<'_, Message> {
fn source(app: &App) -> View<'_, Message> {
use crate::source_navigation::Event as SourceEvent;
let (undo_label, undo_message) = match app.source_rename_undo_message() {
Some(message) => ("Undo rename", Some(message)),
None => (
"Undo model",
(app.document.can_undo() && !app.source_dirty()).then_some(Message::Undo),
),
};
let navigation: View<'_, Message> = if app.source_navigation.open {
column![
row![
@@ -1019,7 +1034,7 @@ fn source(app: &App) -> View<'_, Message> {
),
action("Next", Message::SourceNavigation(SourceEvent::Next(false))),
label(app.source_navigation.label()),
action("Close", Message::SourceNavigation(SourceEvent::Close)),
action("Close", app.source_find_close_message()),
]
.spacing(6)
.align_y(iced::Center),
@@ -1113,8 +1128,13 @@ fn source(app: &App) -> View<'_, Message> {
}
}
let editor = widget::text_editor(&app.source_editor)
.id("source-editor")
.id(app.source_editor_id())
.on_action(Message::SourceEdit)
.key_binding({
let context = app.source_symbol_context();
let rename = app.source_rename_begin();
move |press| source_binding(press, &context, Some(&rename))
})
.font(Font::MONOSPACE)
.size(14)
.padding(16)
@@ -1123,8 +1143,7 @@ fn source(app: &App) -> View<'_, Message> {
app.source_snapshot.clone(),
crate::highlight::format,
);
column![
container(
let header = container(
column![
row![
container(heading(
@@ -1142,8 +1161,8 @@ fn source(app: &App) -> View<'_, Message> {
row![
action("Undo text", Message::SourceUndo),
action("Redo text", Message::SourceRedo),
button(text("Undo model").size(12)).padding([8,10]).style(style::nav)
.on_press_maybe((app.document.can_undo() && !app.source_dirty()).then_some(Message::Undo)),
button(text(undo_label).size(12)).padding([8,10]).style(style::nav)
.on_press_maybe(undo_message),
button(text("Redo model").size(12)).padding([8,10]).style(style::nav)
.on_press_maybe((app.document.can_redo() && !app.source_dirty()).then_some(Message::Redo)),
action("Find / go to…", Message::SourceNavigation(SourceEvent::Open(false))),
@@ -1167,17 +1186,511 @@ fn source(app: &App) -> View<'_, Message> {
"Undo text affects this file's draft. Model Undo restores accepted files together (100 changes / about 32 MiB)."
}),
navigation,
row![
action("Definition · F12", app.source_symbol_message(crate::source_navigation::SymbolEvent::Query(crate::source_navigation::query::Action::Definition))),
action("References · Shift F12", app.source_symbol_message(crate::source_navigation::SymbolEvent::Query(crate::source_navigation::query::Action::References))),
action("Rename alias · F2", app.source_rename_message()),
button(text("Back · Alt ←").size(12)).padding([8, 10]).style(style::nav)
.on_press_maybe((app.source_symbols.back.iter().any(|entry| entry.session == app.source_workspace.session())).then(|| app.source_symbol_message(crate::source_navigation::SymbolEvent::Back))),
].spacing(7),
scrollable(diagnostics)
.height((visible_diagnostics as f32 * 32.).min(132.))
]
.spacing(12)
)
.padding(18),
widget::sensor(editor).key((app.source_workspace.active.clone(),app.source_jump))
.on_show(|_| Message::SourceViewport).on_resize(|_| Message::SourceViewport)
.padding(18);
let editor = widget::sensor(editor)
.key((
app.source_workspace.active.clone(),
app.source_reveal_ticket(),
))
.on_show({
let ticket = app.source_reveal_ticket();
move |_| Message::SourceViewport(ticket)
})
.on_resize({
let ticket = app.source_reveal_ticket();
move |_| Message::SourceViewport(ticket)
});
let workspace: View<'_, Message> = if app.source_symbols.open {
row![
container(editor).width(Fill).height(Fill),
container(scrollable(source_symbols::panel(app)))
.width(300)
.height(Fill),
]
.height(Fill)
.into()
} else {
container(editor).width(Fill).height(Fill).into()
};
source_layout(header.into(), workspace, app.window_size.height)
}
fn source_layout<'a, Renderer: iced::advanced::text::Renderer + 'a>(
header: View<'a, Message, iced::Theme, Renderer>,
workspace: View<'a, Message, iced::Theme, Renderer>,
window_height: f32,
) -> View<'a, Message, iced::Theme, Renderer> {
// Lint clears and repopulates diagnostics asynchronously. Reserve the same
// outer slot so a pointer aimed at the editor cannot land in the header.
column![
container(scrollable(header).id("source-header")).height((window_height * 0.42).max(180.)),
workspace,
]
.height(Fill)
.into()
}
pub(crate) fn source_binding(
press: widget::text_editor::KeyPress,
context: &crate::source_navigation::SymbolContext,
rename: Option<&crate::app::source_rename::Begin>,
) -> Option<widget::text_editor::Binding<Message>> {
use crate::source_navigation::{SymbolEvent, query::Action};
use iced::keyboard::{Key, key::Named};
use widget::text_editor::{Binding, Status};
if matches!(press.status, Status::Focused { .. })
&& press.modifiers.is_empty()
&& press.key == Key::Named(Named::F2)
&& let Some(begin) = rename
{
return Some(Binding::Custom(Message::SourceRename(
crate::app::source_rename::Event::Begin(begin.clone()),
)));
}
// Windows owns Alt+Space for its window menu. Iced's default binding would
// otherwise insert a supplied space payload, even after that menu closes.
// Keep Ctrl+Alt (AltGr), shifted input, and ordinary Space unchanged.
#[cfg(target_os = "windows")]
if matches!(press.status, Status::Focused { .. })
&& press.modifiers == iced::keyboard::Modifiers::ALT
&& matches!(
press.key.as_ref(),
Key::Named(Named::Space) | Key::Character(" ")
)
{
return None;
}
if matches!(press.status, Status::Focused { .. })
&& !press.modifiers.control()
&& !press.modifiers.logo()
{
let event = match &press.key {
Key::Named(Named::F12) if !press.modifiers.alt() => {
Some(SymbolEvent::Query(if press.modifiers.shift() {
Action::References
} else {
Action::Definition
}))
}
Key::Named(Named::ArrowLeft) if press.modifiers.alt() && !press.modifiers.shift() => {
Some(SymbolEvent::Back)
}
_ => None,
};
if let Some(event) = event {
return Some(Binding::Custom(Message::SourceSymbols(
context.clone(),
event,
)));
}
}
Binding::from_key_press(press)
}
#[cfg(all(test, debug_assertions))]
pub(crate) mod source_tests {
use super::*;
use iced::advanced::{
Layout, Shell, graphics, layout, renderer, text as shaped, widget as core_widget,
};
use iced::widget::column;
use iced::{Background, Color, Pixels, Point, Rectangle, Size, Transformation, Vector};
// Measure real Iced paragraphs/editor text without constructing a window or GPU.
pub(crate) struct FontLayout;
impl renderer::Renderer for FontLayout {
fn start_layer(&mut self, _: Rectangle) {}
fn end_layer(&mut self) {}
fn start_transformation(&mut self, _: Transformation) {}
fn end_transformation(&mut self) {}
fn reset(&mut self, _: Rectangle) {}
fn fill_quad(&mut self, _: renderer::Quad, _: impl Into<Background>) {}
fn allocate_image(
&mut self,
handle: &iced::advanced::image::Handle,
callback: impl FnOnce(
Result<iced::advanced::image::Allocation, iced::advanced::image::Error>,
) + Send
+ 'static,
) {
renderer::Renderer::allocate_image(&mut (), handle, callback);
}
}
impl shaped::Renderer for FontLayout {
type Font = Font;
type Paragraph = graphics::text::Paragraph;
type Editor = graphics::text::Editor;
const ICON_FONT: Font = Font::DEFAULT;
const CHECKMARK_ICON: char = '0';
const ARROW_DOWN_ICON: char = '0';
const SCROLL_UP_ICON: char = '0';
const SCROLL_DOWN_ICON: char = '0';
const SCROLL_LEFT_ICON: char = '0';
const SCROLL_RIGHT_ICON: char = '0';
const ICED_LOGO: char = '0';
fn default_font(&self) -> Font {
Font::DEFAULT
}
fn default_size(&self) -> Pixels {
Pixels(16.)
}
fn fill_paragraph(&mut self, _: &Self::Paragraph, _: Point, _: Color, _: Rectangle) {}
fn fill_editor(&mut self, _: &Self::Editor, _: Point, _: Color, _: Rectangle) {}
fn fill_text(&mut self, _: shaped::Text, _: Point, _: Color, _: Rectangle) {}
}
#[derive(Default)]
struct Geometry {
header: Option<(Rectangle, Rectangle, Vector)>,
editor: Option<Rectangle>,
}
impl core_widget::Operation for Geometry {
fn traverse(&mut self, visit: &mut dyn FnMut(&mut dyn core_widget::Operation)) {
visit(self);
}
fn container(&mut self, id: Option<&core_widget::Id>, bounds: Rectangle) {
if id == Some(&core_widget::Id::new("test-source-editor")) {
self.editor = Some(bounds);
}
}
fn scrollable(
&mut self,
id: Option<&core_widget::Id>,
bounds: Rectangle,
content: Rectangle,
offset: Vector,
_: &mut dyn core_widget::operation::Scrollable,
) {
if id == Some(&core_widget::Id::new("source-header")) {
self.header = Some((bounds, content, offset));
}
}
}
fn mounted_source<'a>(
content: &'a widget::text_editor::Content<FontLayout>,
diagnostics: usize,
find: bool,
window_height: f32,
) -> View<'a, Message, iced::Theme, FontLayout> {
let mut notices = column![].spacing(5);
for index in 0..diagnostics {
notices = notices.push(button(text(format!(
"救援/assess.arcadia:{}:5 · Warning: verify this participant's engineering allocation", index + 1,
)).size(12)).padding([4, 6]).width(Fill));
}
let find: View<'_, Message, iced::Theme, FontLayout> = if find {
column![
text_input("Find literal text", "assess").on_input(|s| Message::SourceNavigation(
crate::source_navigation::Event::Query(s)
)),
text_input("Line", "1").on_input(|s| Message::SourceNavigation(
crate::source_navigation::Event::Line(s)
)),
]
.spacing(8)
.into()
} else {
Space::new().into()
};
let header = container(
column![
text("Textual model").size(24),
text("Edit the current file. Apply text validates the complete included model.")
.size(11),
row![
button(text("Apply text")),
button(text("Undo text")),
button(text("Model Undo"))
]
.spacing(8),
text("救援/assess.arcadia · All files applied to the accepted model").size(11),
text("Undo text affects this draft. Model Undo restores accepted files together.")
.size(11),
find,
row![
button(text("Definition · F12")),
button(text("References · Shift F12")),
button(text("Back"))
]
.spacing(7),
scrollable(notices).height((diagnostics as f32 * 32.).min(132.)),
]
.spacing(12),
)
.padding(18);
let editor = container(
widget::text_editor(content)
.on_action(Message::SourceEdit)
.font(Font::MONOSPACE)
.size(14)
.padding(16)
.height(Fill),
)
.id("test-source-editor")
.height(Fill)
.width(Fill);
source_layout(header.into(), editor.into(), window_height)
}
#[test]
fn source_header_keeps_editor_bounds_stable_through_lint_and_find_rebuilds() {
for (host, window_height) in [
(Size::new(720., 540.), 700.),
(Size::new(1180., 890.), 1080.),
] {
let content = widget::text_editor::Content::<FontLayout>::with_text(
"// is excluded\r\n// 雨\r\n",
);
let mut tree = core_widget::Tree::empty();
let mut baseline = None;
for (diagnostics, find) in [
(0, false),
(6, false),
(0, false),
(6, true),
(1, true),
(0, false),
] {
let mut ui = mounted_source(&content, diagnostics, find, window_height);
tree.diff(ui.as_widget());
let node = ui.as_widget_mut().layout(
&mut tree,
&FontLayout,
&layout::Limits::new(Size::ZERO, host),
);
let mut geometry = Geometry::default();
ui.as_widget_mut().operate(
&mut tree,
Layout::new(&node),
&FontLayout,
&mut geometry,
);
let editor = geometry.editor.unwrap();
let (header, _, _) = geometry.header.unwrap();
let slot = node.children()[0].bounds();
assert_eq!(slot.height, (window_height * 0.42).max(180.));
assert!(
header.height <= slot.height,
"short content may shrink inside the fixed slot"
);
assert!(
editor.height >= 240.,
"remaining editor must stay usable: {editor:?}"
);
assert_eq!(editor.y, slot.y + slot.height);
if let Some(expected) = baseline {
assert_eq!(editor, expected, "diagnostics={diagnostics}, find={find}");
} else {
baseline = Some(editor);
}
}
}
}
#[test]
fn source_header_remains_scrollable_and_preserves_offset_across_diagnostic_refresh() {
let content = widget::text_editor::Content::<FontLayout>::with_text("// 雨\r\n");
let host = Size::new(720., 540.);
let mut tree = core_widget::Tree::empty();
let mut saved = None;
for diagnostics in [6, 7] {
let mut ui = mounted_source(&content, diagnostics, true, 700.);
tree.diff(ui.as_widget());
let node = ui.as_widget_mut().layout(
&mut tree,
&FontLayout,
&layout::Limits::new(Size::ZERO, host),
);
let mut geometry = Geometry::default();
ui.as_widget_mut()
.operate(&mut tree, Layout::new(&node), &FontLayout, &mut geometry);
let (bounds, contents, _) = geometry.header.unwrap();
assert!(
contents.height > bounds.height,
"fixture must actually overflow"
);
if saved.is_none() {
let mut messages = Vec::new();
let mut shell = Shell::new(&mut messages);
ui.as_widget_mut().update(
&mut tree,
&iced::Event::Mouse(iced::mouse::Event::WheelScrolled {
delta: iced::mouse::ScrollDelta::Pixels { x: 0., y: -45. },
}),
Layout::new(&node),
iced::mouse::Cursor::Available(Point::new(bounds.x + 8., bounds.y + 8.)),
&FontLayout,
&mut iced::advanced::clipboard::Null,
&mut shell,
&Rectangle::with_size(host),
);
assert!(shell.is_event_captured());
}
let mut geometry = Geometry::default();
ui.as_widget_mut()
.operate(&mut tree, Layout::new(&node), &FontLayout, &mut geometry);
let offset = geometry.header.unwrap().2;
assert!(offset.y > 0., "the actual mounted Scrollable must move");
if let Some(before) = saved {
assert_eq!(offset, before);
} else {
saved = Some(offset);
}
}
}
#[cfg(target_os = "windows")]
#[test]
fn source_editor_windows_menu_payload_is_inert_but_space_and_altgr_still_edit() {
use core_widget::operation::Focusable;
use iced::keyboard::{
self, Key, Modifiers,
key::{Code, Named, Physical},
};
use widget::text_editor::{Binding, Content, KeyPress, State, Status};
let baseline = "// is excluded\r\n// 雨\r\n";
let context = crate::source_navigation::SymbolContext {
session: Id::new_v4(),
path: "救援/assess.arcadia".into(),
};
for (key, physical_key, modifiers, payload, inserted) in [
(
Key::Named(Named::Space),
Physical::Code(Code::Space),
Modifiers::ALT,
" ",
false,
),
(
Key::Character(" ".into()),
Physical::Code(Code::Space),
Modifiers::ALT,
" ",
false,
),
(
Key::Named(Named::Space),
Physical::Code(Code::Space),
Modifiers::empty(),
" ",
true,
),
(
Key::Named(Named::Space),
Physical::Code(Code::Space),
Modifiers::CTRL | Modifiers::ALT,
" ",
true,
),
(
Key::Character("e".into()),
Physical::Code(Code::KeyE),
Modifiers::CTRL | Modifiers::ALT,
"€",
true,
),
(
Key::Named(Named::Space),
Physical::Code(Code::Space),
Modifiers::ALT | Modifiers::SHIFT,
" ",
true,
),
] {
let mut content = Content::<FontLayout>::with_text(baseline);
content.move_to(widget::text_editor::Cursor {
position: widget::text_editor::Position { line: 0, column: 5 },
selection: None,
});
let press = KeyPress {
key: key.clone(),
modified_key: key.clone(),
physical_key,
modifiers,
text: Some(payload.into()),
status: Status::Focused { is_hovered: false },
};
assert!(
matches!(
Binding::<Message>::from_key_press(press),
Some(Binding::Insert(_))
),
"the supplied event must expose the default insertion path"
);
let mut messages = Vec::new();
{
let mut editor: View<'_, Message, iced::Theme, FontLayout> =
widget::text_editor(&content)
.on_action(Message::SourceEdit)
.font(Font::MONOSPACE)
.size(14)
.padding(16)
.height(Fill)
.key_binding(|press| source_binding(press, &context, None))
.into();
let mut tree = core_widget::Tree::new(editor.as_widget());
let size = Size::new(600., 240.);
let node = editor.as_widget_mut().layout(
&mut tree,
&FontLayout,
&layout::Limits::new(Size::ZERO, size),
);
tree.state
.downcast_mut::<State<shaped::highlighter::PlainText>>()
.focus();
let event = iced::Event::Keyboard(keyboard::Event::KeyPressed {
key: key.clone(),
modified_key: key,
physical_key,
location: keyboard::Location::Standard,
modifiers,
text: Some(payload.into()),
repeat: false,
});
let mut shell = Shell::new(&mut messages);
editor.as_widget_mut().update(
&mut tree,
&event,
Layout::new(&node),
iced::mouse::Cursor::Unavailable,
&FontLayout,
&mut iced::advanced::clipboard::Null,
&mut shell,
&Rectangle::with_size(size),
);
}
assert_eq!(
messages.len(),
usize::from(inserted),
"modifiers={modifiers:?}"
);
for message in messages {
let Message::SourceEdit(action) = message else {
panic!("unexpected navigation action");
};
content.perform(action);
}
let expected = if inserted {
format!("// is{payload} excluded\r\n// 雨\r\n")
} else {
baseline.into()
};
assert_eq!(content.text(), expected);
}
}
}
fn checks(app: &App) -> View<'_, Message> {
let issues = &app.model_issues;
let mut out = column![heading(
@@ -0,0 +1,260 @@
use crate::{
app::{App, Message},
source_navigation::{
SymbolEvent,
query::{self, Declaration, Disposition, Evidence, Identity, Membership, Position},
},
style,
};
use iced::{
Element, Fill,
widget::{Space, button, column, container, row, scrollable, text, tooltip},
};
pub(super) fn panel(app: &App) -> Element<'_, Message> {
let state = &app.source_symbols;
if !state.open
|| (state.results.is_none() && state.in_flight.is_none() && state.notice.is_none())
{
return column![].into();
}
let title = state.results.as_ref().map_or_else(
|| "Source symbols".to_owned(),
|results| {
let action = match results.action {
query::Action::Definition => "Definitions",
query::Action::References => "References",
};
results.alias.as_ref().map_or_else(
|| action.to_owned(),
|alias| format!("{action} · @{}", preview(alias, 40)),
)
},
);
let mut content = column![
row![
text(title).size(13),
Space::new().width(Fill),
button(text("Close").size(11))
.padding([3, 8])
.style(style::nav)
.on_press(app.source_symbol_message(SymbolEvent::Close)),
]
.align_y(iced::Center)
]
.spacing(5);
if let Some(notice) = &state.notice {
content = content.push(super::label(preview(notice, 240)));
}
if state.in_flight.is_some() {
content = content.push(super::label("Finding source symbols…"));
} else if let Some(results) = &state.results {
let stale = results.stamp.snapshot != app.source_key();
if stale {
content = content.push(super::label(
"Stale results — source changed. Run Definition or References again.",
));
}
let scope = &results.scope;
content = content.push(super::label(format!(
"{} · {} · {} included / {} detached / {} unverified files · {} scope issues",
if scope.partial() {
"Partial scope"
} else {
"Complete include scope"
},
if !scope.applied {
"Unapplied drafts"
} else if scope.validated {
"Validated sources"
} else {
"Draft sources"
},
scope.included_files,
scope.detached_files,
scope.unverified_files,
scope.issues.len(),
)));
let explanation = match results.disposition {
Disposition::NoSymbol => "Place the caret on a declaration alias or an @reference.",
Disposition::NoDefinition => "No matching declaration in the loaded sources.",
Disposition::Choices => {
"Choose a declaration; draft and detached candidates need an explicit choice."
}
Disposition::Direct => "Definition in the current sources.",
Disposition::LexicalReferences => {
"Lexical uses of this alias; these do not establish a semantic target."
}
};
content = content.push(super::label(explanation));
if results.total_definitions > 1 {
content = content.push(super::label(format!(
"Alias collision: {} declarations. Uses are not attributed to a single declaration.",
results.total_definitions,
)));
}
let enabled = !stale && !app.busy;
let mut rows = column![super::label(counts(
"Declarations",
results.definitions.len(),
results.total_definitions,
results.omitted_definitions,
))]
.spacing(4);
for (index, definition) in results.definitions.iter().enumerate() {
rows = rows.push(location_row(
declaration_title(&definition.declaration),
&definition.path,
definition.position,
provenance(
definition.membership,
definition.evidence,
definition.declaration.identity,
false,
),
enabled.then(|| {
app.source_symbol_message(SymbolEvent::Choose {
stamp: results.stamp,
reference: false,
index,
})
}),
));
}
rows = rows.push(super::label(counts(
"Lexical uses",
results.references.len(),
results.total_references,
results.omitted_references,
)));
for (index, reference) in results.references.iter().enumerate() {
let title = reference.context.as_ref().map_or_else(
|| format!("@{} · lexical use", preview(&reference.alias, 48)),
|context| {
format!(
"@{} · inside {}",
preview(&reference.alias, 48),
declaration_title(context)
)
},
);
rows = rows.push(location_row(
title,
&reference.path,
reference.position,
provenance(
reference.membership,
reference.evidence,
reference
.context
.as_ref()
.map_or(Identity::Missing, |context| context.identity),
true,
),
enabled.then(|| {
app.source_symbol_message(SymbolEvent::Choose {
stamp: results.stamp,
reference: true,
index,
})
}),
));
}
let row_count = results.definitions.len() + results.references.len();
content =
content.push(scrollable(rows).height((44.0 + row_count as f32 * 48.0).min(180.0)));
}
container(content)
.padding(8)
.width(Fill)
.style(style::subtle)
.into()
}
fn counts(label: &str, shown: usize, total: usize, omitted: usize) -> String {
format!("{label}: {total} total · {shown} shown · {omitted} omitted")
}
fn declaration_title(declaration: &Declaration) -> String {
let name = declaration
.name
.as_ref()
.map_or_else(String::new, |name| format!(" \"{}\"", preview(name, 48)));
format!(
"{}{} · @{}",
preview(&declaration.kind, 24),
name,
preview(&declaration.alias, 48)
)
}
fn provenance(
membership: Membership,
evidence: Evidence,
identity: Identity,
context: bool,
) -> String {
let membership = match membership {
Membership::Included => "Included",
Membership::Detached => "Detached",
Membership::Unverified => "Unverified",
};
let evidence = match evidence {
Evidence::Validated => "Validated",
Evidence::Draft => "Draft",
};
let collision = match identity {
Identity::Collision { count } => format!(
" · {}ID collision ({count})",
if context { "Context " } else { "" },
),
Identity::Missing | Identity::Unique(_) => String::new(),
};
format!("{membership} · {evidence}{collision}")
}
fn location_row(
title: String,
path: &str,
position: Position,
status: String,
event: Option<Message>,
) -> Element<'static, Message> {
let line = position.line.saturating_add(1);
let column = position.byte_column.saturating_add(1);
let location = format!("{}:{line}:{column}", preview(path, 72));
tooltip(
button(
column![
text(title).size(12),
super::label(format!("{location} · {status}"))
]
.spacing(2),
)
.padding([4, 6])
.width(Fill)
.style(style::nav)
.on_press_maybe(event),
text(format!(
"{path}:{line}:{column} (1-based line and UTF-8 byte column)"
))
.size(11),
tooltip::Position::Top,
)
.into()
}
/// Keep headings compact without copying the remainder of a long admitted value.
fn preview(value: &str, limit: usize) -> String {
let mut chars = value.chars();
let mut result: String = chars
.by_ref()
.take(limit)
.map(|ch| if ch.is_whitespace() { ' ' } else { ch })
.collect();
if chars.next().is_some() {
result.push('…');
}
result
}
+56
View File
@@ -2633,6 +2633,62 @@ trace links, occurrence identity, comments and file ownership. Each open file
retains its own unapplied draft across file navigation. Located lint diagnostics
refer to the raw draft bytes rather than an identity-stabilized intermediate.
Property editing MUST NOT silently discard a pending source draft.</p>
<p>In Textual model, place the caret on a declaration alias or an <span class="docutils literal">&#64;reference</span>
and choose <strong>Definition</strong> (<span class="docutils literal">F12</span>) or <strong>References</strong> (<span class="docutils literal">Shift+F12</span>).
<strong>Back</strong> (<span class="docutils literal">Alt+Left</span>) returns to the previous source location in this
workspace. These shortcuts act while the source editor has focus; the Text
toolbar also exposes the actions. If the previous draft changed, Back restores
its current cursor rather than reusing an obsolete selection.</p>
<p>Symbol navigation reads bounded snapshots of the currently loaded source
drafts. It does not apply drafts or load missing included files. The results
identify partial scope, draft evidence, detached or unverified files, alias
ambiguity and authored-ID collisions. Draft, detached and ambiguous definition
candidates require an explicit row choice. References are lexical uses of an
alias, not a list of resolved typed relationships; comments and strings are
excluded. Declaration and use counts include any rows omitted by the result
limits. If sources change, stale rows cannot navigate: run the query again.
Navigation MUST preserve the accepted model and every source draft, and select
locations in the original UTF-8 bytes. Displayed locations use one-based lines
and UTF-8 byte columns.</p>
<p><strong>Rename alias</strong> (<span class="docutils literal">F2</span> while the source editor has focus) changes the alias
under the caret or its exact selection. It requires a unique authored identity
in the complete accepted source bundle, with no pending source, property or
behavior drafts and no extra loaded detached files. Accepted but unsaved source
is eligible. The operation MUST NOT implicitly apply a draft or allocate an ID.
The engineering name and UUID remain unchanged.</p>
<p>The <strong>Source alias</strong> field does not trim or normalize the entered alias. Pasting
line breaks, tabs or other control characters is explicitly rejected as a whole:
the field and its selection remain unchanged, and any previous preview approval
is invalidated. <strong>Preview</strong>
prepares a typed alias change and displays every changed file and source line;
comments, strings, engineering data, file membership and declaration ownership
remain unchanged. Enter in the field requests Preview, never confirmation.
The preview is for this operation against accepted source, so a later Save may
also contain earlier accepted edits. A changing rename requires enough model
history capacity to retain its immediate Undo. An invalid, identical, stale or
oversized candidate cannot enable confirmation.</p>
<p>The preview MUST provide access to all admitted files, hunks, lines and long-line
segments. Refuse a candidate whose complete preview exceeds the editor's bounds:
256 changed files, 50,000 changed lines or 8 MiB of displayed source bytes
(both versions of changed/context lines and file paths). Index metadata is
separately bounded to seven retained line records per changed line. These
limits do not restrict the language itself. A changed-line count is not a count
of semantic references. Cancel, Preview and Rename alias remain reachable
outside the independently scrolling source preview.</p>
<p>Explicit <strong>Rename alias</strong> confirms the current preview once, as one accepted
model/source transaction. A source, document, recovery or replacement change
invalidates its approval even if later bytes match the old preview. Closing the
form cancels approval; a late worker result MUST NOT reopen it. Rejected,
canceled and unchanged operations preserve accepted bytes, drafts, save state,
revisions, selection and both histories. Successful rename selects the new alias
at the original occurrence rather than the first matching spelling in the file.
Editing the replacement permits a new Preview in the same form. After a source
context change, close the form and invoke Rename again on the current alias.</p>
<p><strong>Undo rename</strong> is guarded against intervening edits and uses model history;
the persistent <strong>Undo model</strong> and <strong>Redo model</strong> controls restore the complete
accepted snapshots. Text <span class="docutils literal">Ctrl+Z</span> remains <strong>Undo text</strong>. Save is separate and
uses the ordinary guarded source-save contract. An unconfirmed preview and Undo
history are not persisted on reopening.</p>
<p>Changing a graphical UUID must atomically update map keys and every reference.
Alias changes preserve UUID identity. Deletion must account for owned elements,
incident relationships, ordered occurrences, and diagram placements without
+63
View File
@@ -2054,6 +2054,69 @@ retains its own unapplied draft across file navigation. Located lint diagnostics
refer to the raw draft bytes rather than an identity-stabilized intermediate.
Property editing MUST NOT silently discard a pending source draft.
In Textual model, place the caret on a declaration alias or an ``@reference``
and choose **Definition** (``F12``) or **References** (``Shift+F12``).
**Back** (``Alt+Left``) returns to the previous source location in this
workspace. These shortcuts act while the source editor has focus; the Text
toolbar also exposes the actions. If the previous draft changed, Back restores
its current cursor rather than reusing an obsolete selection.
Symbol navigation reads bounded snapshots of the currently loaded source
drafts. It does not apply drafts or load missing included files. The results
identify partial scope, draft evidence, detached or unverified files, alias
ambiguity and authored-ID collisions. Draft, detached and ambiguous definition
candidates require an explicit row choice. References are lexical uses of an
alias, not a list of resolved typed relationships; comments and strings are
excluded. Declaration and use counts include any rows omitted by the result
limits. If sources change, stale rows cannot navigate: run the query again.
Navigation MUST preserve the accepted model and every source draft, and select
locations in the original UTF-8 bytes. Displayed locations use one-based lines
and UTF-8 byte columns.
**Rename alias** (``F2`` while the source editor has focus) changes the alias
under the caret or its exact selection. It requires a unique authored identity
in the complete accepted source bundle, with no pending source, property or
behavior drafts and no extra loaded detached files. Accepted but unsaved source
is eligible. The operation MUST NOT implicitly apply a draft or allocate an ID.
The engineering name and UUID remain unchanged.
The **Source alias** field does not trim or normalize the entered alias. Pasting
line breaks, tabs or other control characters is explicitly rejected as a whole:
the field and its selection remain unchanged, and any previous preview approval
is invalidated. **Preview**
prepares a typed alias change and displays every changed file and source line;
comments, strings, engineering data, file membership and declaration ownership
remain unchanged. Enter in the field requests Preview, never confirmation.
The preview is for this operation against accepted source, so a later Save may
also contain earlier accepted edits. A changing rename requires enough model
history capacity to retain its immediate Undo. An invalid, identical, stale or
oversized candidate cannot enable confirmation.
The preview MUST provide access to all admitted files, hunks, lines and long-line
segments. Refuse a candidate whose complete preview exceeds the editor's bounds:
256 changed files, 50,000 changed lines or 8 MiB of displayed source bytes
(both versions of changed/context lines and file paths). Index metadata is
separately bounded to seven retained line records per changed line. These
limits do not restrict the language itself. A changed-line count is not a count
of semantic references. Cancel, Preview and Rename alias remain reachable
outside the independently scrolling source preview.
Explicit **Rename alias** confirms the current preview once, as one accepted
model/source transaction. A source, document, recovery or replacement change
invalidates its approval even if later bytes match the old preview. Closing the
form cancels approval; a late worker result MUST NOT reopen it. Rejected,
canceled and unchanged operations preserve accepted bytes, drafts, save state,
revisions, selection and both histories. Successful rename selects the new alias
at the original occurrence rather than the first matching spelling in the file.
Editing the replacement permits a new Preview in the same form. After a source
context change, close the form and invoke Rename again on the current alias.
**Undo rename** is guarded against intervening edits and uses model history;
the persistent **Undo model** and **Redo model** controls restore the complete
accepted snapshots. Text ``Ctrl+Z`` remains **Undo text**. Save is separate and
uses the ordinary guarded source-save contract. An unconfirmed preview and Undo
history are not persisted on reopening.
Changing a graphical UUID must atomically update map keys and every reference.
Alias changes preserve UUID identity. Deletion must account for owned elements,
incident relationships, ordered occurrences, and diagram placements without
+12837 -12837
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -1,3 +1,9 @@
> Historical record — superseded on 2026-09-11. Live plans, ownership and blockers
> were migrated once to [Gitea issue 1, comment 408](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/1#issuecomment-408)
> and [issue 2](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/2).
> Do not update this as a live ledger. [STATE.md](STATE.md) links the verified integrated result.
> The historical text below is preserved; its old active-status wording is not current guidance.
# First release execution plan
Updated 2026-09-11, Codex-9e8r6t `/root`.
+121 -317
View File
@@ -1,338 +1,142 @@
# Progress Ledger — first release
# Integrated checkpoint — first release
Updated 2026-09-11, Codex-9e8r6t `/root`, Windows host.
**Release remains unaccepted. Windows/product work continues; Linux is paused by the user.**
The [restart handoff](RESTART_HANDOFF.md) preserves the earlier pause; current
results and capacity constraints below supersede its active-status wording.
Updated 2026-09-13 UTC (September 12 locally) by Codex-9e8r6t `/root`, Windows host.
**Full OA/SA release acceptance is incomplete. Linux work remains user-paused.**
## Objective and current source
[PROJECT_GOAL.md](../PROJECT_GOAL.md) owns the application requirements.
Current objective attachment `9467fa86-4606-4fe2-93ec-122137d03079` was read in full.
Instruction synchronization `b70bf1d` preserves the user specification and
[AGENTS.md](../AGENTS.md). It changes instructions, not the verified package inputs.
Deliver the complete OA/SA first release in [PROJECT_GOAL.md](../PROJECT_GOAL.md).
The latest authoritative attachment is
`815ff7b9-73c4-41a2-a809-635ecf8389d6/goal-objective.md`, read in full and preserved
in that file. It requires constraints/calculations, quantities/units and reusable
libraries, plus uncluttered human/AI text-only modeling at small and large scale.
Long homogeneous lists and poor behavior editing remain explicit concerns.
## Delivered Windows milestone
Local branch: `codex/release1-9e8r6t`, substantive source checkpoint
`df6f59562643b7771ecf0c972f8655f3e3f1c4da`, committed, pushed and read back.
It follows the user's instruction sync `07eb3cd`.
The preceding committed and pushed code/package checkpoint is
`27df4a3945ebc97cd7cbde61f6aeea7a91c680d3`. It includes named behavior creation,
source CLI, the nine CLI packaging changes and reviewed evidence. Source CLI
semantic commit `01b76a1`, packaging assembly `a0a48e8` and release integration
`27df4a3` are distinct. Contextual prerequisite creation, its reports/oracle and
40 raw evidence files are integrated in `df6f595`; native acceptance continues.
All 238 frozen build inputs and 44 exact index artifacts passed before commit.
Gitea issue 1 records the handoff in comment 242. Remote AGENTS.md at blob
`4b8465c8993107062ad2974c15a958d449530e92` adds the maintenance instructions
announced in comment 229: concise current entrypoints, durable history and
coordinated preservation rather than indiscriminate deletion.
[Source alias rename prerelease](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/releases/tag/v0.2.0-preview.rename.20260912)
was published and read back on September 13 at 00:47:52 UTC. Extract the whole ZIP
and run `arcadia-studio.exe`, keeping its sibling `libunwind.dll`. Studio, the
optional REST server, examples, offline help and dependency notices are included.
## Current acceptance checkpoint — postboot work
Both executables come from **cbc49a7802fb1bba0dd284fd904c700a0703ae70**; the tag
identifies that exact source. Evidence-only checkpoint **506a349b** holds the
completed source/package/runtime/native reports and independent reviews. All
559 package files and all three downloaded release assets were verified.
The binaries use development profiles; this is a prerelease.
CLI publication evidence `d95b1ab` and complete OA native evidence `c4bad4b` are
also pushed and read back. The reboot checkpoint preserves reviewed layout/owner
caption WIP, native evidence and interrupted compiler records; it is not a new
accepted build. This update follows published reboot checkpoint
`ca53f574e57381a523e946d5277b4081cff74355`; the newer results follow below.
After successive user reboots, the latest observed boot is13:59:33.500 UTC.
The GUI adds F2 alias rename with a complete preview, explicit confirmation,
origin selection, immediate Undo Rename and explicit Save. Strict Clippy,
805 desktop tests, the isolated Confirm timing check and 501 core/server tests
passed. Actual packaged GUI checks covered minimum-size simple and 30-source
workflows, all six representative changed lines, Undo/Redo/Save and representative
reopening. Eight exact saved-state checks preserve model/identity/source and all
41 final physical fixture files. Normal GUI closure returned 0 with empty logs.
The packaged server separately passed 23 HTTP/disk persistence/restart checks.
Each result retains its precise scope.
The postboot focused3 gate reached a real terminal before that reboot:25 passed,
one new long-parent fixture assertion failed; no production visibility assertion
failed. A reviewed test-only stronger fixture is frozen for focused4, preserving
the same215-pixel host and all visibility guarantees. Automatic approval review
blocked both exact proposed incremental-cache removal attempts before execution,
with only `blocked by policy`; no deletion ran. Nondeleting NTFS compression
recovered capacity instead. The incremental-cache pass was partially applied
then intentionally stopped; the generated-binary pass completed exit0 across
282 files with every SHA256 unchanged. C had11,777,519,616 bytes free afterward.
Supported Ubuntu26.04 installation finished exit0 at14:36:46 UTC (session32405),
with10.51GB host space remaining. First actual root shell reports Ubuntu26.04
LTS, x86_64 Linux6.18.33.2-microsoft-standard-WSL2 and a mounted root filesystem.
A systemd root-user-session warning remains recorded. The user316 mirrored/DNS
settings were applied and runtime mirrored mode verified, but the guest had only
loopback, no route and failed DNS/HTTPS. Read-only host IPv6 evidence is a cause
hypothesis only; no global registry/adapter/VPN/firewall change was made. User328
now supersedes that trial with VirtioProxy and explicitly makes AmneziaWG
immutable, including inspection. Its exact VirtioProxy-only config is saved;
both the initial startup and one persistent root-shell retry after compilation
ended with CreateVm/0x800705b4 before guest commands. A distinct WslService-only
restart then failed at Windows service access; it remains Running. No elevation
workaround, extra launch or other service/network change followed. This is a
startup timeout, not a measured VirtioProxy network failure. Root rechecked the
Gitea issue through comment348 after renewed user steering: owner328 remains
the latest posted solution and is already applied. Verified official Rust archives
and all60 exact Ubuntu packages are prepared via Windows HTTPS; Ubuntu
signature verification and installation remain mandatory. Windows
focused4 passed26/26 after11m05 compile and9.54s test execution, retaining every
geometry assertion. Strict all-target Clippy and workspace format also passed.
Matching GUI compilation also passed; session87425 is terminal and no compiler
lease remains live. Immutable GUI SHA256 is
`5657BAB5C841939B66F901EFE6C0FFB2D7CBBE8CC5F111A0CA3DE8073D3846CE`.
All238 actual source inputs were rehashed unchanged. After the26 affected tests,
the immutable complete desktop executable passed all679 tests at15:47:53 UTC,
zero failed/ignored/filtered, exit0, one test thread and ordinary Windows stack.
The user subsequently directed that Linux builds and
checking be skipped until they notify us that WSL networking is resolved. Linux
setup, launches, diagnostics, builds and checks are paused; preserve current
configuration and inputs. This direction is recorded in Gitea comment356 and
supersedes service-access next steps. See
[WSL readiness](release-wsl-readiness-9e8r6t-20260911.md).
See the [publication record](release-source-alias-rename-published-20260912.md),
[package acceptance and limits](release-source-alias-rename-package-20260912.md),
and [source validation](release-source-alias-rename-validation-20260912.md).
A known P2 Details-to-Preview delayed-scroll-reset lifetime gap remains disclosed;
the separately owned correction/union is not part of this frozen package.
Fresh GUI5657 v2 Lifeline baseline opened through the native file picker. At
1100x700 client size with both panels, child Name, Activity, OA root and pinned
Back/Use controls were visible; a maximize/restore retained both raw names.
The completed recovery record passed exact accepted-baseline, raw parent/child,
kind/root and reserved-ID checks before a controlled isolated process stop.
Recovery restored an unsaved local copy with an exactly equal accepted baseline
and authored behavior/identities. Child Escape retained the parent; a new blank
child, temporary Use and parent Cancel left nothing to undo. Save As to a fresh
destination passed the unchanged core oracle with exactly two source files.
The isolated process closed normally. A fresh direct Lifeline trial subsequently
passed actual Create-before-Save, one Undo/Save and one Redo/Save against the
complete independent model/source/original-ID contract. Fresh Machine owner
visibility at minimum size, actual Create and open, one Undo/Save, one Redo/Save
and real-picker reopen/SA/Save also pass the unchanged complete contract. All
new source and consumer identities persist; Undo retains only the two proven
generated files. The final six-file reopen equals Redo exactly, and all isolated
native processes closed normally. See the
[v2 native report](release-contextual-source-native-v2-20260911.md).
## Previous Windows milestone
Peer956 comment338 reserves our bounded syntax-only language outline seam;
their codec/lifecycle scope remains separate. The query experiment is private,
uncompiled and not integrated. The current design is
[text navigation](release-text-navigation-design-20260911.md); a discovered
Unicode path-collision mismatch is being corrected in a separate proposal.
Independent outline review additionally requires rejecting noncanonical UUID
spellings as authored navigation anchors and recommends folding paths once.
Root verified the parser mismatch; the author is preparing a separate v2 patch.
[Source navigation prerelease](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/releases/tag/v0.2.0-preview.navigation.20260911)
was published and read back on September 12 at 10:54:02 UTC. Extract the whole ZIP and run
`arcadia-studio.exe`; keep its sibling `libunwind.dll`. Studio, the optional REST
server, examples, offline help and dependency notices are included.
- CLI `BAD169F8…E3559`: author 12/12, strict all-target Clippy/format/build pass;
independent 183 assertions across 21 fresh processes pass. All four committed
experiment files retain their measured bytes. JSON describes complete changed
files, not a saved whole-candidate plan. See the two source-CLI reports.
- Contextual source first frozen artifact `6E677F58…8CC0`: focused 22/22 and full
desktop 675/675 pass, 448.33 seconds execution. The later inactive-source origin
bypass and guide wording are fixed and independently reviewed. Final source
across 13 desktop files passed 23 focused tests, 3 guide tests, strict all-target Clippy,
matching GUI build and formatting. GUI SHA256 starts `52DE82E4`; its test
inventory is 676. There is no full 676-suite pass. Root verified the frozen
inputs/executable and launched PID 7212 in the isolated
`.local/native-qa/contextual-source-20260911-v1` stage. Lifeline Save-adoption
and Chain direct Create each pass complete model/source and one Undo/Redo.
Machine direct Create/Save and Undo/Save pass; its Redo remains pending.
A fresh-profile postboot Open/SA view/Save now passes complete six-file model,
source and original identities. That GUI closed normally. See
[native results](release-contextual-source-native-20260911.md).
- Native scenario B3: both OA use-return paths pass wide and minimum sizes;
both SA paths pass minimum focused canvas. Pending disabled Open preserves the
draft; explicit Cancel/Save matches exact baseline. B2 OA Action, nested State,
explicitly bound Reuse and Fragment all pass independent complete Project and
two-source Create/Save, one Undo/Save and one Redo/Save predictions, retaining
original exact identities. Final OA reopen/Save also passes. SA B2 remains
pending locally; B3's earlier size/layer scopes are unchanged. See
[local scenario native evidence](release-scenario-native-local-20260911.md).
- Root published GUI/server release **1**, `v0.2.0-preview.authoring.20260911`,
at 12:40:51 UTC, using source `2ec72d4`, D4D9 GUI and EFEE server.
ZIP `664F30B6…` has 559 files and passed
strict notices, independent complete archive/source correspondence, clean GUI
launch/example/Save/help/close and server create/get/restart persistence. All
three release assets passed full downloaded readback. Reports/raw evidence are
committed in `6a61061`; see [GUI/server publication](release-authoring-prerelease-published-20260911.md).
This is a prerelease, not full OA/SA acceptance.
- Root published CLI release **2**, `cli-v0.2.0-preview.authoring.20260911`, at
12:50:39 UTC. Tag and release readback match `27df4a3`, draft false and
prerelease true. ZIP `2B051F8C…` has 114 files, 27 notice packages and exact
BAD169F8/F456 executable/runtime. Independent clean CLI 156 assertions across
10 invocations pass; all three uploaded assets passed downloaded hash readback.
[Publication report](release-cli-prerelease-published-20260911.md) preserves
the exact records and distinguishes local CRLF notes from the public LF body.
The tag points to exact raw-input reconstruction **802855f7**, based on corrected
source **33c6d83** and distinct from the original build capture. The
package pairs GUI B183 with the unchanged, separately verified EFEE server.
All 559 package files and all three downloaded release assets were verified.
The binaries use the development profile; this is a prerelease.
## Completed work and scoped evidence
The GUI adds Definition/References/Back for current Text drafts and corrects
repair/recovery saved-state handling. All 755 desktop tests passed (one ignored),
with strict Clippy, formatting and a matching build. Earlier navigation native
checks cover minimum-size interaction, ambiguous/partial scope and the 30-file
engineering workflow; the corrected binary separately passed repair/rollback,
Close/Cancel and exact Save checks. Fresh package acceptance verified Home/help,
native Open, navigation, edit/Undo, Apply, Save and complete saved-model/source
equality. Independent server checks verified exact API content and persistence
across restart. Each result retains its specific build and workflow scope.
- Palette inline naming and focused Escape: `7d1df4f`, independently published as
`codex/palette-authoring-20260910`. Candidate 2 focused tests, GUI build and
strict desktop Clippy passed. Its native F2 rename/Save/Undo/Redo matched exact
three-file expectations; Entity creation matched the complete independent
model/source oracle. Candidate 3 completed ordinary Activity, existing placement,
allocation, direct Interaction and F2: complete basic model/four sources PASS.
Explicit SA actor/destination transition passed complete model/six sources;
Undo four-source baseline, Redo six-source result and reopen all passed. Six
physical files are byte-identical across reopen/reuse-preview Cancel/Save.
Immutable checkpoints/logs: `.local/native-qa/palette-20260910-v3/`.
- Recovery naming autofocus: `31b7dc3`, 13 focused checkpoint tests passed after
integrated compilation. The later SA behavior draft's native recovery,
autofocus and Escape evidence is recorded in the creation report below.
- Other-host behavior/topology/scenario/history: original `01bb52a` integrated
as `057eddd`; constructor cache fix `b6b76ef` integrated as `a70de55`; explicit
history seed fix `4ecad78` cherry-picked as `81668f9`.
- Corrected immutable desktop artifact completed **631/631 passed**, 408.18 seconds,
exit 0; all three prior 618-artifact failures are fixed. Exact artifact/logs in
`.local/scenario-workspace-20260910/tests-81668f9/`. It covers `3978bbe` workspace,
Back/OpenUse guards and both history fixes, but not later Sensor/creation work.
- A real same-size owner/document Sensor regression led to `d114a27`; affected
scenario 53/53 passed. Historical native candidate 3 predates that correction.
Mounted workspace tests cover 500×570 and wide geometry; later local native
B2/B3 results have the separate scopes recorded above.
- Named local creation passed final 21/21 and guide 3/3 after ancestry-label
correction. The matching immutable desktop suite passed **653/653**, 362.83 seconds,
zero failures/ignored; exact artifact `864B0F…E86` and logs under
`.local/behavior-creation-20260911/tests-final`. Independent integration review
found no additional correctness blocker. Strict Clippy with all targets and
`-D warnings`, plus workspace formatting, pass after one behavior-equivalent history_fields let-chain
correction; affected history 63/63 and matching GUI rebuild pass. This frozen
creation GUI is `gui-verified` SHA D4D9C2BD…B20C31. At actual 1100×700 client size,
named OA Process, explicit ParticipantInteraction Scenario with capability
context and SA owner-linked State machine plus requested first view passed
complete independent Project/SourceBundle checks at 7/8/9 files. Each single
Undo/Redo preserved exact expected semantics, sources and role identities.
Reopen/Save retained all nine physical source files byte-for-byte. Wide/minimum
draft cancellations retained the initial six files exactly. Detailed report:
[native creation](release-behavior-creation-native-20260911.md).
- Independent creation oracle v2 corrects a harness assumption: Save retains
known detached source files after Undo. Full Project and reachable source
equality remain mandatory; the complete physical inventory must equal the
explicit pre-Undo checkpoint overlaid with expected reachable bytes. Unknown,
changed or missing retained files fail. No product defect was hidden by this
correction; see [oracle review](release-behavior-creation-oracle-20260911.md).
- Fresh source-7 constructor probes passed 54 explicit/omitted comparisons and
12 required-field refusals across OA/SA, with complete typed models, canonical
reparse and exact authored no-op/name-edit retention. Constructor and Scenario
default wording now describes current behavior; strict HTML regeneration
passed. Other constructor families are explicitly outside this evidence.
See [default review](release-constructor-defaults-review-20260911.md).
- Source schema checks passed: 72 fixtures, 204 schemas, 14 families, 90 scalar
leaves. API/language reST rendered with strict docutils without warnings.
- Packaging committed `b98f135`: portable Linux adapter, shared package checks,
Docker input validation and exact upstream notices. Independent review found
and fixed five concrete defects. Python 11/11 and PowerShell contracts pass.
Historical Windows-input ZIP has 557 files; real Linux notices close over
339 packages/681 files. Linux archive adapter used inert ELF fixtures, not
actual current application binaries. Exact Fira/Cantarell notice Git bytes
were independently verified. Later exact GUI/server and CLI packages have
their own regenerated notices and published artifact evidence above.
- Independent native Capella creation study completed, saved and closed cleanly;
report `release-capella-creation-study-20260910.md` is complete. Viewpoint-first
naming and distinct local create/existing selection inform the implementation.
- Textual usability audit completed three static tasks and example counts. The
existing grammar already permits omitted initial IDs/defaults; key gaps are
cross-file reference context, safe alias refactoring and reviewed patches.
Source-7 EBNF/schema documentation and viewpoint omission guidance are corrected;
generated language HTML passed strict docutils. Both concise snippets passed
26 real REST requests: identity-only stabilization, exact no-op/name edit,
stale/invalid nonmutation and restart persistence. All 120 current core/server
files match the preserved source-7 binary's documented snapshot. This closes
the bounded recipe gap, not large-model or native text-editor acceptance. The
verified recipe is now `examples/text-first` and in the language reference.
Authoritative records:
Detailed evidence: [integrated gates](release-integrated-gates-20260910.md),
[palette native](release-palette-native-20260910.md),
[scenario workspace](release-scenario-workspace-20260910.md),
[creation design](release-local-behavior-creation-20260910.md),
[packaging implementation](release-packaging-implementation-20260910.md),
[independent packaging review](release-packaging-independent-review-20260910.md).
- [Publication, artifacts and limitations](release-navigation-prerelease-published-20260912.md)
- [Per-binary preparation](release-navigation-prerelease-preparation-20260911.md)
and [independent archive/server review](release-navigation-prerelease-review-20260911.md)
- [Fresh native package acceptance](release-navigation-prerelease-native-20260911.md)
and [integrated navigation evidence](release-text-navigation-integrated-20260911.md)
- [Previous contextual authoring milestone](release-contextual-source-prerelease-published-20260911.md)
- [Verified code/evidence checkpoint](release-postboot-checkpoint-review-20260911.md)
- [Standalone CLI prerelease](release-cli-prerelease-published-20260911.md),
supplying checked source stabilization and typed alias rename separately
## Active ownership and execution
## Material unfinished scope
Root owns integration, native input, commits, publication and Wiki updates.
GUI5657 native trials and the complete679 desktop tests are terminal; no owned
Studio, compiler or test process remains. All Linux actions are user-paused.
Current-draft Definition/References/Back was implemented in source checkpoint
**[36db9356](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/commit/36db9356cce3c7614ae37eec9fe17678ca210afe)**.
The [initial native trial](release-text-navigation-native-initial-20260911.md)
found four interaction defects. Their [correction](release-text-navigation-native-corrections-20260911.md)
at **eeeaa126** passed 188 focused tests, the full 750-test desktop suite and
strict Clippy, with exact input readback and independent review. Matching GUI5478
[native evaluation](release-text-navigation-native-v3-20260911.md) verified those
fixes, ambiguous/partial source navigation, and the 30-file engineering workflow;
explicit Save preserved complete models, identities and source bytes. It also
found a repair-mode false-clean status against the prior saved destination.
Its [saved-baseline correction](release-text-repair-save-state-20260911.md)
at **33c6d83** passes the full 755-test suite, strict Clippy and matching GUI B183
build. Its [native repair verification](release-text-repair-save-native-v4-20260911.md)
passed missing-include and duplicate-alias repairs plus interrupted-save rollback:
Apply/Recover retain unsaved status, Close warns, Cancel retains work, and explicit
Save yields exact complete model/identity/source equality. The fresh package
passed its separate native and independent server checks and is now delivered above.
The [integrated evaluation](release-text-navigation-integrated-20260911.md) links
exact input archives, earlier full-test scope and independent findings.
The published contextual preview remains unchanged.
- `release_audit`: full-suite/recovery archives frozen; now audits updated
Windows package inputs and per-binary source provenance without building.
- `behavior_audit`: Lifeline evidence frozen; prepares separately reviewed v2
bounded outline/query proposals. No production application or compiler lease.
- `linux_readiness`: Linux remains paused. Completed independent outline review;
now preserves only the completed Windows Machine evidence.
- Codex-956atf: owns chooser/workspace/focus, shared canvas shell and isolated
schema8/local-definition core. Reported focus5/5, analysis28/28 and numeric26/26
plus core Clippy; codec/lifecycle work remains separate. None of that later
peer source is integrated locally. Our bounded language outline seam is
reserved by comment338; source8/codec ownership remains theirs.
- Codex-ytr83r: owns external B4 Scene/lifetime integration and Linux packaging.
Linux work is paused; peer host results cannot substitute for local execution.
The latest rename release does not yet contain newer peer canvas/chooser and
scenario-lifetime work, complete constraints/calculations, dimensional quantities,
maintained model libraries.
Those additions require coherent graphical/text/REST realization and validation.
Some scenario forms retain old scroll positions and dense labels remain crowded.
Local SA action/state/reuse/fragment and supplementary camera/focus tasks retain
explicit unfinished scopes in [scenario evidence](release-scenario-native-local-20260911.md).
User issue2/comment250 calls for consistent, domain-constrained interactive
diagrams, not necessarily arbitrary placement. Codex-956atf owns the shared
canvas-shell implementation in an isolated worktree (comment261). Existing
technical Canvas widgets and source cards do not close this requirement.
Local Ubuntu26.04 is installed; the last two startup attempts timed out before
guest execution. Preserve that history and verified inputs while waiting for
the user's explicit notice that WSL networking is resolved.
Optimized builds, remaining real engineering workflows and a fresh independent
cross-disciplinary end-state review remain necessary. Old MVP exclusions and
individual passing tests do not reduce the user's full requirements.
Verified bundles for `eb5161b` and `4ecad78` are retained in
`.local/integration-20260910`. Local refs `codex/behavior-snapshot-eb5161b` and
`codex/history-seed-20260910` preserve exact commits. B4 lifetime projection and
its guide delta are not integrated yet; coordinate shared scene wiring. Review
found insertion versus lifetime bounds, activation after branch-local Delete and
unassigned-lane map differences that must be addressed before acceptance.
Ubuntu/WSL setup and all Linux diagnostics/builds/checks are paused until the user
explicitly reports networking resolved. Preserve existing configuration, caches
and evidence. [WSL readiness](release-wsl-readiness-9e8r6t-20260911.md) owns the
historical attempts; it is not a current Linux application acceptance claim.
## Unresolved requirements and gates
## Coordination and history
1. Finish native basic supplementary move/camera/focus/minimum matrix and current
scenario/process/state tasks. Main basic/transition/history/reopen passed at
wide size. Check raw drafts, recovery, exact source and real task completion.
2. Publish the verified contextual missing-source/source-form milestone with
truthful Windows package inputs. Named and contextual creation/history/reopen
pass; operand-editing and qualified Action allocation remain separate work.
3. Constraints/calculations and quantity compatibility are currently descriptive
metadata; same-project includes are not maintained cross-project libraries.
Peer schema 8/local-definition implementation is now ratified and staged in
its isolated worktree (Gitea comment 231); local integration and all required
representations/acceptance remain pending. See [library review brief](release-library-candidate-review-20260910.md).
Other-host proposals expose cosmetic package revision/type compatibility,
subjectless analysis closure and text-only instance normalization decisions;
full reports and paired criticism are now available from verified `c6d296a`.
Its 218-assertion maintenance experiment supports explicit baseline values
with one-level Case overrides; complete freeze and effective-case evaluation
are required. Refined baseline/library contracts remain active externally.
4. Build on the published standalone CLI and compare language improvements using
both local usability and complete other-host proposals.
Current grammar+tooling, domain syntax, namespaces and portable identity
modules remain distinct candidates. Concise examples/CLI alone do not prove
uncluttered modular engineering authoring or safe large-model changes.
5. Run coherent current desktop/core/server, specification, examples, REST and
optimized packaging gates after integration. Prior passes remain scoped.
6. Obtain current Linux runtime acceptance through the external owner's supported
guest route. Local WSL2 import failed with HCS_E_HYPERV_NOT_INSTALLED and no
distro registered; this host still has no usable Linux runtime. Preserve
recorded route failures and do not repeat a rejected workaround.
7. Fresh independent cross-disciplinary release review remains required after
actual workflow and semantic acceptance, with all material findings resolved.
The user requested splitting oversized [issue 1](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/1).
Live coordination now uses focused [behavior/canvas](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/2),
[activity movement](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/3),
[child work](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/4),
[lifecycle Windows acceptance](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/5),
[source navigation](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/6),
[quantities/calculations](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/7),
[maintained libraries](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/8),
and [Text alias rename](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/9).
Read current comments for ownership and execution state; this checkpoint does
not track active leases.
[Authoring Wiki](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/wiki/Authoring20260911)
is the shared entrypoint. Durable decisions remain in [DECISIONS.md](DECISIONS.md)
and topic reports; the [text-navigation design](release-text-navigation-design-20260911.md)
records the current bounded design and its falsifiers.
The [Text alias-rename proposal](release-source-alias-rename-design-20260911.md)
and [critique](release-source-alias-rename-critique-20260911.md) retain the original
design rationale; current implementation and verified scope are recorded in the
[published package report](release-source-alias-rename-package-20260912.md).
## Handoff and publication
Use Gitea issue #1 and current Wiki to coordinate as **Codex-9e8r6t**. Read before
resuming; preserve the other host's work. User issue 1 comment 178 authorizes programmatic
reuse of existing MCP credentials for Git/REST without printing or committing them.
Authenticated non-force push and remote readback now pass; current branch is
available directly. Historical bundle transfers remain reproducible. Integration `3978bbe` was published and
independently fetched/hash-verified as a Git bundle on
`codex/integration-transfer-20260910`; Wiki `Integration3978bbe` and issue #97 own
exact transfer instructions. Other host has integrated it and an equivalent
Sensor fix. Creation `4bb4aaf` was likewise published on
`codex/integration-transfer-20260911`, file
`harness/transfers/creation-4bb4aaf.bundle.b64`: decoded 105022 bytes,
SHA256 `0DEFAE91A56430076C432758F923BC0675911DA9FA7588C9961FF15F47EAEBF6`,
prerequisite `3978bbe`. Anonymous Git readback, strict base64 length/hash check and
`git bundle verify` passed; issue #128 gives selective integration instructions.
Corrected oracle/native/default evidence is published as `2ec72d4` on the same
branch, file `harness/transfers/evidence-2ec72d4.bundle.b64`: decoded 185563 bytes,
SHA256 `F74E14EE394BCC026E24987C8526AA7E769DDE748FE38117532824EC19AE159F`,
prerequisite `4bb4aaf`. Anonymous readback/hash and bundle verification pass (#150).
Preserve the other hosts' B4/reference chooser/design work and avoid duplicates.
Other-host `c6d296a` transfer is verified and imported as local
`codex/behavior-snapshot-c6d296a`: 334830 bytes,
SHA256 `526A80E2D32ED0E57A7B2372B5F02D4652E8751DFEBA81953C4F045225D6AACB`,
prerequisite `1797516`, from `codex/behavior-transfer-20260910` file
`harness/transfers/behavior-c6d296a.bundle.b64`. Selected analysis/library/text
reports, criticism, experiments and independent scenario oracle are restored;
51 evidence files compare byte-for-byte with Git blobs. No source/ledger merge.
Issue comments 136/143 and Wiki `Authoring20260911` record the handoff.
The old ledgers, including all historical platform and native evidence, were
archived byte-for-byte before this consolidation in
[history/2026-09-10-ledgers-before-second-consolidation](history/2026-09-10-ledgers-before-second-consolidation/STATE.md),
with hashes.json. Their historical-current wording does not supersede this file.
Legacy TASK_LEDGER/PLAN live content was migrated once in
[comment 408](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/1#issuecomment-408).
Those files are marked historical. Previous detailed STATE was preserved
[byte-for-byte](history/2026-09-11-state-before-gitea-migration/STATE.md), including
failed attempts, prior releases, transfer paths and earlier evidence links.
Do not restore historical active-status or environment-next-step wording.
+6
View File
@@ -1,3 +1,9 @@
> Historical record — superseded on 2026-09-11. Live plans, ownership and blockers
> were migrated once to [Gitea issue 1, comment 408](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/1#issuecomment-408)
> and [issue 2](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/2).
> Do not update this as a live ledger. [STATE.md](STATE.md) links the verified integrated result.
> The historical text below is preserved; its old active-status wording is not current guidance.
# Task Ledger — first release
Updated 2026-09-11 by Codex-9e8r6t `/root`. Full release not accepted.
@@ -0,0 +1,56 @@
# Contextual Windows prerelease evidence — 2026-09-11
This frozen whitelist preserves **118 original payloads, 4,913,769 bytes**, for
ZIP `9186d4fc9a7b52fb195c183c4847c8e3419ea6da8b3f907e0c06f9ceec58dee0`.
Every copied payload was matched to its original by byte length and SHA256.
`manifest.json` maps original repository-relative paths to archive paths;
`readback.json` records the scoped receipt/source/module/file comparisons.
No application, oracle or compiler was rerun during preservation.
| Directory | Evidence and interpretation |
| --- | --- |
| `producer/` | Exact source reconstruction, original build references, initial wrapper failure before Cargo, corrected single-metadata packaging pass, package metadata/notices/checksums, producer readback and source-only branch publication. |
| `reviewer/` | Independent artifact and packaged-server results, executed reviewer helpers, seven exact HTTP response bodies/receipts, runtime logs and the persisted model envelope. Server termination/restart is explicit, not a graceful-drain claim. |
| `native/initial/` | Initial real GUI trial, screenshots, environment/module records, one added literal `%SystemDrive%` cache-path receipt, separate model-only oracle pass and exact three-file checkpoint. The package-inventory guard failed; the later model-only pass does not waive it. |
| `native/v2/` | Corrected fresh-profile trial, real Create-before-Save screenshots, complete-model/three-file oracle pass, module inventory, normal-close observation and unchanged 559-file package receipt. Numeric GUI exit code was not observed. |
| `native/helpers/` | Exact original and v2 launch/check helpers. V2 adds standard Windows paths/private Desktop and changes trial/extraction containment; artifact, oracle and complete-package guards remain intact. |
`native/report-before-v2.md` is the historical pending report, retained as such.
The current [native report](../../release-contextual-source-prerelease-gui-20260911.md)
states the actual v2 PASS. The frozen [producer report](../../release-contextual-source-prerelease-preparation-20260911.md)
and [independent review](../../release-contextual-source-prerelease-review-20260911.md)
remain separate. Original paths inside raw helpers/receipts describe the executed
environment; copying a helper into this archive does not make its old paths portable.
No executables, DLLs, ZIP binary, caches, full extraction, private profile or
duplicate working copy is included. Both exact `checkpoint-first/` trees equal
their respective working copies and recorded file maps. The large historical
source tar and previous release's notice inventory are referenced by original
path/hash in the manifest instead of being duplicated. The Windows cache itself
stays in the preserved first extraction; only its exact delta/hash receipt is here.
Manifest SHA256: `0e57281db42b37af1fb7b970d34f361c936240c593c3a8fea780ac89eac4f6ac`.
Readback SHA256: `1a8231064eb722b38178e0569e8b331bbd4d7fdcc9a7e28a34d7e1be33ad74fc`.
These cover the 118 copied payloads and their verification. This README and the
two staging lists are generated navigation aids, not additional raw observations.
Publication receipts belong to root's separate record and are not in this manifest.
## Byte-preserving staging
Root owns Git staging. Suggested precise `.gitattributes` addition, **not applied
by this archiver**, after the existing general text rules:
```gitattributes
harness/experiments/contextual-prerelease-20260911/** -text
```
`staging-paths.txt` enumerates exactly **124 paths**: these **123 archive files**
plus the current native report. `force-add-paths.txt` identifies the **18 `.log`
payloads** ignored by current rules. An explicitly bounded staging command is:
```powershell
git add -f --pathspec-from-file=harness/experiments/contextual-prerelease-20260911/staging-paths.txt
```
The path list excludes later publication records and all unrelated source work.
Root should compare staged blob bytes to the manifest before committing.
@@ -0,0 +1,18 @@
harness/experiments/contextual-prerelease-20260911/producer/prepare.log
harness/experiments/contextual-prerelease-20260911/producer/package.log
harness/experiments/contextual-prerelease-20260911/producer/package2.log
harness/experiments/contextual-prerelease-20260911/producer/source-push.log
harness/experiments/contextual-prerelease-20260911/producer/readback.log
harness/experiments/contextual-prerelease-20260911/producer/evidence/gui-build.log
harness/experiments/contextual-prerelease-20260911/native/initial/baseline.stderr.log
harness/experiments/contextual-prerelease-20260911/native/initial/baseline.stdout.log
harness/experiments/contextual-prerelease-20260911/native/initial/stderr.log
harness/experiments/contextual-prerelease-20260911/native/initial/stdout.log
harness/experiments/contextual-prerelease-20260911/native/initial/model-only.stderr.log
harness/experiments/contextual-prerelease-20260911/native/initial/model-only.stdout.log
harness/experiments/contextual-prerelease-20260911/native/v2/baseline.stderr.log
harness/experiments/contextual-prerelease-20260911/native/v2/baseline.stdout.log
harness/experiments/contextual-prerelease-20260911/native/v2/stderr.log
harness/experiments/contextual-prerelease-20260911/native/v2/stdout.log
harness/experiments/contextual-prerelease-20260911/native/v2/saved.stderr.log
harness/experiments/contextual-prerelease-20260911/native/v2/saved.stdout.log
@@ -0,0 +1,735 @@
{
"createdUtc": "2026-09-11T16:56:13.168177+00:00",
"scope": "Exact whitelist archive; records preserve actual producer, independent review and both native trials. No application/test rerun.",
"entries": [
{
"source": ".local/contextual-prerelease-20260911/prepare.py",
"path": "producer/prepare.py",
"bytes": 12841,
"sha256": "8a92989460bef90a8b7e3eb3c57d525628d79db672f72037d74d0a772a79f92c"
},
{
"source": ".local/contextual-prerelease-20260911/prepare.log",
"path": "producer/prepare.log",
"bytes": 3657,
"sha256": "21cd606d005afe12ffcf4790ab28a345d8ec7022f7a7bf816ef70ca819febd14"
},
{
"source": ".local/contextual-prerelease-20260911/prepare-result.json",
"path": "producer/prepare-result.json",
"bytes": 121,
"sha256": "142a6351b40bc78708215fe819898e8bacd076e9bff834f47bf012c0694cbf32"
},
{
"source": ".local/contextual-prerelease-20260911/preparation.json",
"path": "producer/preparation.json",
"bytes": 47935,
"sha256": "01076682a763fca6c6941422b54fed02f1b7f2483c550c51a936b5bdfdbac594"
},
{
"source": ".local/contextual-prerelease-20260911/committed-roundtrip.json",
"path": "producer/committed-roundtrip.json",
"bytes": 39327,
"sha256": "2f687aa82fa066594dfc6ec82aa2aaafdbea01912305c1a052ef11fb8ba6eb3e"
},
{
"source": ".local/contextual-prerelease-20260911/evidence-manifest.json",
"path": "producer/evidence-manifest.json",
"bytes": 3459,
"sha256": "4d9e047a3f23664421db0404cd25ccad870067b5021b617ef4137cacdef4bdab"
},
{
"source": ".local/contextual-prerelease-20260911/build-evidence.json",
"path": "producer/build-evidence.json",
"bytes": 2367,
"sha256": "16d1ab0df520cd7bb80e2bad89a066b47d4de366929b96a828405a1971d957ec"
},
{
"source": ".local/contextual-prerelease-20260911/package.ps1",
"path": "producer/package.ps1",
"bytes": 3566,
"sha256": "0a7d7bf06dfa32f37635d293a52d425b940999739e32da05b10ee4407564d068"
},
{
"source": ".local/contextual-prerelease-20260911/package.log",
"path": "producer/package.log",
"bytes": 365,
"sha256": "65601750bb248b8c59f98a78d6f593011af2f7eafafb1dc1e0eb379695a7c879"
},
{
"source": ".local/contextual-prerelease-20260911/package-result.json",
"path": "producer/package-result.json",
"bytes": 399,
"sha256": "4ceafa4d20f4e30a1bcbe096c775da8b5db52eb045a15f2308b5df7bbe09590d"
},
{
"source": ".local/contextual-prerelease-20260911/package2.ps1",
"path": "producer/package2.ps1",
"bytes": 3811,
"sha256": "98f43e1f409823c52dc1ec492adbdb2f6a75779c55106bcd2ed2e630744f55a4"
},
{
"source": ".local/contextual-prerelease-20260911/package2.log",
"path": "producer/package2.log",
"bytes": 513,
"sha256": "6a260f0978be503a35547c1637a61ac0b27eb71bf314d19eb8b44bf48f8b42b6"
},
{
"source": ".local/contextual-prerelease-20260911/package2-result.json",
"path": "producer/package2-result.json",
"bytes": 291,
"sha256": "aaf0c838ea8335c40f7b5d20f48e6c4c2eb282aa338e0ffac350dab229ebbb91"
},
{
"source": ".local/contextual-prerelease-20260911/metadata2-result.json",
"path": "producer/metadata2-result.json",
"bytes": 533,
"sha256": "0a76097d93fbc7fcd2a770ed5a1b4ffe6d3afdd6a0e3c9f76cbc4c95b6fb6a0e"
},
{
"source": ".local/contextual-prerelease-20260911/push-source.py",
"path": "producer/push-source.py",
"bytes": 3856,
"sha256": "4e64842fd8389909b7c11e1f5a04c0459f7987255628598ed2dd19b71641d01f"
},
{
"source": ".local/contextual-prerelease-20260911/source-push.log",
"path": "producer/source-push.log",
"bytes": 851,
"sha256": "5c71bdf121e90f80b611698a700b6d7d512d2f558e48a17076c03282cb00946b"
},
{
"source": ".local/contextual-prerelease-20260911/source-push-result.json",
"path": "producer/source-push-result.json",
"bytes": 447,
"sha256": "b98699bac76974d644179565163049259c195c9ca7c4c7fadd92c27f2ada4bea"
},
{
"source": ".local/contextual-prerelease-20260911/readback.py",
"path": "producer/readback.py",
"bytes": 3510,
"sha256": "ef93f489cbea50d419588d89f7d10902f168bdd8d95979649b570180fb99b9ad"
},
{
"source": ".local/contextual-prerelease-20260911/readback.log",
"path": "producer/readback.log",
"bytes": 2669,
"sha256": "c4d7070f987304ec5b6050ac3da209449787b99bd035529afa3ef66df2d391bd"
},
{
"source": ".local/contextual-prerelease-20260911/package-readback.json",
"path": "producer/package-readback.json",
"bytes": 99379,
"sha256": "af8fcc11f1ad863df0861ac248a48391f635bdeef484978b0b9c4732a6593268"
},
{
"source": ".local/contextual-prerelease-20260911/delivery-manifest.json",
"path": "producer/delivery-manifest.json",
"bytes": 4162,
"sha256": "9b48aa787d0cc2026b411c5c8a7a1ef97cb84eda06c3e06cc0dd3cd0cf373867"
},
{
"source": ".local/contextual-prerelease-20260911/packages/ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm/package.json",
"path": "producer/package-metadata/package.json",
"bytes": 76309,
"sha256": "25f01823dbceed15468bf759eed3f9ffbfd1098427027288bcbb9a3d356b6a4d"
},
{
"source": ".local/contextual-prerelease-20260911/packages/ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm/dependency-notices.json",
"path": "producer/package-metadata/dependency-notices.json",
"bytes": 1619822,
"sha256": "f318f87e6a23dcfac16ef7b1cfe51ecb804e98e1ff6a97271180319d5922fc0e"
},
{
"source": ".local/contextual-prerelease-20260911/packages/ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm/documentation-check.json",
"path": "producer/package-metadata/documentation-check.json",
"bytes": 43,
"sha256": "bcc89585951fd9e5a1641993c51ca79e00a7a06944a8273d2df413331320e93f"
},
{
"source": ".local/contextual-prerelease-20260911/packages/ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm/SHA256SUMS.txt",
"path": "producer/package-metadata/SHA256SUMS.txt",
"bytes": 66376,
"sha256": "04e4be3f6a081e11ccad8609643031d91fed82cd08e7c7821002ff9b9a04e454"
},
{
"source": ".local/contextual-prerelease-20260911/packages/ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm.zip.sha256",
"path": "producer/package-metadata/ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm.zip.sha256",
"bytes": 144,
"sha256": "21455af55f6330235a72f43f09bd155acaea0d647bd3f68f09a64d06a21fdbcc"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/gui-inputs4.json",
"path": "producer/evidence/gui-inputs4.json",
"bytes": 44198,
"sha256": "669724858967d83ab7da5f78bfafb6065e2bcab3bad0e68d0a74feb86c7195e7"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/gui-stage-manifest.json",
"path": "producer/evidence/gui-stage-manifest.json",
"bytes": 641,
"sha256": "4beb64b955aecf5ae3bfb606316ec1fc9d17d288ed85023515148bb1890f034f"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/gui-build-status.json",
"path": "producer/evidence/gui-build-status.json",
"bytes": 232,
"sha256": "aced28a87b7306ad6112496768be0154adeb307b60f21172c4ee4ca72e534731"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/gui-build.log",
"path": "producer/evidence/gui-build.log",
"bytes": 157,
"sha256": "73e2dec6d40e99059b1a89b0f3602239f2df1abac6dde99104679b0b2b04c4a7"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/gui-clippy-status.json",
"path": "producer/evidence/gui-clippy-status.json",
"bytes": 257,
"sha256": "03046af19cfc7b5be86fdfc06f5ec542b9f33e94f8121b23236602bdbaca8383"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/gui-fmt-status.json",
"path": "producer/evidence/gui-fmt-status.json",
"bytes": 187,
"sha256": "7b8f8ebfb1989cc3bd00e98f49afcf1e533939b50242a6177b8a4e5238641a3f"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/gui-focused26-status.json",
"path": "producer/evidence/gui-focused26-status.json",
"bytes": 293,
"sha256": "9242277158a77a9e96c0121637cfe635dde09217ed9e4109d9f37f8e50710eff"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/gui-full679-result.json",
"path": "producer/evidence/gui-full679-result.json",
"bytes": 669,
"sha256": "a87d2634fe8be05e7de387346a43056db150f1846ac54a18d02650fe81b9c80d"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/server-original-gates.json",
"path": "producer/evidence/server-original-gates.json",
"bytes": 2572,
"sha256": "b7fdfc55ed4c964d276f20f1c57c81c1e924b8da315171089740ab8335ac9f0d"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/server-original-binary-hashes.json",
"path": "producer/evidence/server-original-binary-hashes.json",
"bytes": 744,
"sha256": "110a03e323133efb48d50ad065d41414599aa85e0ac420e7d622aa04df4d54f8"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/server-prior-input-comparisons.json",
"path": "producer/evidence/server-prior-input-comparisons.json",
"bytes": 66465,
"sha256": "3c78dea4e93dae186fd24ab826c6680178a2c7849c270a22deae2ff732f1857b"
},
{
"source": ".local/contextual-prerelease-20260911/evidence/update-audit.md",
"path": "producer/evidence/update-audit.md",
"bytes": 11024,
"sha256": "305f0be41ae2a6d7b29edb51c411a0f229a7f41f4ff1b78a46fc27730a1991f0"
},
{
"source": ".local/contextual-prerelease-review-20260911/artifact-result.json",
"path": "reviewer/artifact-result.json",
"bytes": 500051,
"sha256": "3a6bf2580b25dad696d635dcbbde88522a065f83698229c2a22dda92f2ab6ee8"
},
{
"source": ".local/contextual-prerelease-review-20260911/frozen-inputs.json",
"path": "reviewer/frozen-inputs.json",
"bytes": 423,
"sha256": "e5aadf382b62863a875c08707173dee50423e0d35bb3209642035f8936aa7af2"
},
{
"source": ".local/contextual-prerelease-review-20260911/prepare_review.py",
"path": "reviewer/prepare_review.py",
"bytes": 16502,
"sha256": "1879237f65c00c720ecaa0991381cc6bc8ab3b2948a1b1b7944f09e3d8a7b3e0"
},
{
"source": ".local/contextual-prerelease-review-20260911/review.py",
"path": "reviewer/review.py",
"bytes": 30170,
"sha256": "b2a5eb1e5b01dfacb85a2ab5b5b8516c02a84424a2fb49156d0d7df7634226bc"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-result.json",
"path": "reviewer/server-result.json",
"bytes": 128940,
"sha256": "37fec9e1a1bcaa8a208233fc56fb78a1e607df32271097ab1a946037f04de3af"
},
{
"source": ".local/contextual-prerelease-review-20260911/terminal-readback.json",
"path": "reviewer/terminal-readback.json",
"bytes": 2950,
"sha256": "0d8b2b73381b4618991978735ec561bc706e200a8a64457229662ba4029378dd"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/help.stderr",
"path": "reviewer/server-run/help.stderr",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/help.stdout",
"path": "reviewer/server-run/help.stdout",
"bytes": 350,
"sha256": "99c5cb07d451c6da829b835b66fce92ce5c2529508c8053030123df704d0610e"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/version.stderr",
"path": "reviewer/server-run/version.stderr",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/version.stdout",
"path": "reviewer/server-run/version.stdout",
"bytes": 21,
"sha256": "af82a1126f98794babaa173139764cadbfb5143a235f9a887ef70d18d00a0d91"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/server-1.stderr",
"path": "reviewer/server-run/server-1.stderr",
"bytes": 160,
"sha256": "a13a72054e4e57ae3fa8eb0d636257865d864b163bc26e1d06a67a78c7021445"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/server-1.stdout",
"path": "reviewer/server-run/server-1.stdout",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/server-2.stderr",
"path": "reviewer/server-run/server-2.stderr",
"bytes": 160,
"sha256": "9686dfd32fc6640b966cf1c1cc2f95dbfdbac321a4ac0a9b81f3830fb4311d9b"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/server-2.stdout",
"path": "reviewer/server-run/server-2.stdout",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-01.body",
"path": "reviewer/server-run/http-01.body",
"bytes": 15,
"sha256": "a29ee2b15c494311c52521766e44af56a3ad2248e7a8ab465e5206463c13d288"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-01.json",
"path": "reviewer/server-run/http-01.json",
"bytes": 397,
"sha256": "19806bc0189d6be751f89b752a3c26bc5d0cbe6a91746aa1123fd6ea1f9a3ecc"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-02.body",
"path": "reviewer/server-run/http-02.body",
"bytes": 15,
"sha256": "a29ee2b15c494311c52521766e44af56a3ad2248e7a8ab465e5206463c13d288"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-02.json",
"path": "reviewer/server-run/http-02.json",
"bytes": 403,
"sha256": "1a0055da5f4d866380c51c76abf68211438a29c9827a755d0332dca03a08e62e"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-03.body",
"path": "reviewer/server-run/http-03.body",
"bytes": 359757,
"sha256": "c6ae512f791a939eaf6ec5e5e78e9468bdee0e028092d00098bd90ad9498d967"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-03.json",
"path": "reviewer/server-run/http-03.json",
"bytes": 414,
"sha256": "601c06d27a21511fc9d8f049ee69994171b0ed6a94493ef26b6f3c4bbd31274e"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-04.body",
"path": "reviewer/server-run/http-04.body",
"bytes": 252,
"sha256": "13323e5f458fcfb859679aab013498bed98b79ace01886937820bffc9de34280"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-04.json",
"path": "reviewer/server-run/http-04.json",
"bytes": 542,
"sha256": "9e212d7f72e628af9b2b4c9489ccccfd3f84d2c12f6a13f4b7633151addee1a9"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-05.body",
"path": "reviewer/server-run/http-05.body",
"bytes": 566,
"sha256": "b9763c66414711a92089fe0e44749d1eb19fe4487be3defa890b899fa11da15e"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-05.json",
"path": "reviewer/server-run/http-05.json",
"bytes": 505,
"sha256": "a81bbebfce562b0835739cbce918f7edd875be0595cdc0bd74404f3c8715870e"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-06.body",
"path": "reviewer/server-run/http-06.body",
"bytes": 15,
"sha256": "a29ee2b15c494311c52521766e44af56a3ad2248e7a8ab465e5206463c13d288"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-06.json",
"path": "reviewer/server-run/http-06.json",
"bytes": 403,
"sha256": "feb893aef0ed7923b802b153cddd2f378409badc2e68710a56a351522bfb5850"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-07.body",
"path": "reviewer/server-run/http-07.body",
"bytes": 566,
"sha256": "b9763c66414711a92089fe0e44749d1eb19fe4487be3defa890b899fa11da15e"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/http-07.json",
"path": "reviewer/server-run/http-07.json",
"bytes": 505,
"sha256": "30caeb4cf751a9b6e955f63679daa54ac2514fc9ad2a8870a6303d5918dc55fe"
},
{
"source": ".local/contextual-prerelease-review-20260911/server-run/data/3ab1f047-86a8-435e-8519-c372ddcd87ca.json",
"path": "reviewer/server-run/persisted-envelope.json",
"bytes": 566,
"sha256": "b9763c66414711a92089fe0e44749d1eb19fe4487be3defa890b899fa11da15e"
},
{
"source": ".local/contextual-prerelease-gui-20260911/baseline.json",
"path": "native/initial/baseline.json",
"bytes": 425,
"sha256": "64ad261e2f85e75c396557c8eaadc9203a8761f09c4c5e06c0ac8c043d3b8a20"
},
{
"source": ".local/contextual-prerelease-gui-20260911/baseline.stderr.log",
"path": "native/initial/baseline.stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-gui-20260911/baseline.stdout.log",
"path": "native/initial/baseline.stdout.log",
"bytes": 86,
"sha256": "738f111737ec2cda051e8830f96b4064faab072e5772ca63302a41cdf0c7b541"
},
{
"source": ".local/contextual-prerelease-gui-20260911/created-before-save.jpg",
"path": "native/initial/created-before-save.jpg",
"bytes": 116350,
"sha256": "245149dc458f39b41f59b441fe2b351cbd841768f10b11d4b73e08dc66d8dc0d"
},
{
"source": ".local/contextual-prerelease-gui-20260911/home.jpg",
"path": "native/initial/home.jpg",
"bytes": 98549,
"sha256": "f4ff60737ce83e963d9fab85f1103cd0f5f4f928b6e43a7d070a186d774e6433"
},
{
"source": ".local/contextual-prerelease-gui-20260911/launch.json",
"path": "native/initial/launch.json",
"bytes": 1369,
"sha256": "8149587422e88b556c9d890ef8b4d89c0a02c616d066b43ef23a0dee964a3d4d"
},
{
"source": ".local/contextual-prerelease-gui-20260911/loaded-modules.json",
"path": "native/initial/loaded-modules.json",
"bytes": 6238,
"sha256": "73b9be28610394727213dbb24da776e698b53197a5ee340571a8a5e35004a8b4"
},
{
"source": ".local/contextual-prerelease-gui-20260911/new-activity-ready.jpg",
"path": "native/initial/new-activity-ready.jpg",
"bytes": 115800,
"sha256": "9afe7c34b51db89680e342a178558172159d3cc8e6b2289c18f3469af2f91473"
},
{
"source": ".local/contextual-prerelease-gui-20260911/normal-close.json",
"path": "native/initial/normal-close.json",
"bytes": 283,
"sha256": "ebf672a7b77bb5ad8363400f61ac18d2ce931965556c9557ad8a794240f7f35b"
},
{
"source": ".local/contextual-prerelease-gui-20260911/offline-guide.jpg",
"path": "native/initial/offline-guide.jpg",
"bytes": 170876,
"sha256": "786bbc462322b46d12b127a7d3baacf6034cf3f4839c340e3e9229173ed85545"
},
{
"source": ".local/contextual-prerelease-gui-20260911/package-before.json",
"path": "native/initial/package-before.json",
"bytes": 70373,
"sha256": "e604e6c0f4df3861241d7395a2d4be2d428c5870a7461b948628c23e90290e03"
},
{
"source": ".local/contextual-prerelease-gui-20260911/saved-model.jpg",
"path": "native/initial/saved-model.jpg",
"bytes": 116903,
"sha256": "4d29b07c4741ba5d12685ce82c7311d04a2b48cde281a64b5ca86827ffe156dc"
},
{
"source": ".local/contextual-prerelease-gui-20260911/staged-before-create.jpg",
"path": "native/initial/staged-before-create.jpg",
"bytes": 110100,
"sha256": "eac2bf311a30eacf3ab888febced22ea7685cd4ab7f81ee899f4de318a4e20ff"
},
{
"source": ".local/contextual-prerelease-gui-20260911/stderr.log",
"path": "native/initial/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-gui-20260911/stdout.log",
"path": "native/initial/stdout.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-gui-20260911/model-only-result.json",
"path": "native/initial/model-only-result.json",
"bytes": 1200,
"sha256": "6497d9f0ca8a370d9844d6e48811c38293fbed26adc495713fec8765f10c1e52"
},
{
"source": ".local/contextual-prerelease-gui-20260911/model-only.stderr.log",
"path": "native/initial/model-only.stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-gui-20260911/model-only.stdout.log",
"path": "native/initial/model-only.stdout.log",
"bytes": 81,
"sha256": "ce1401a7002b272d197337c08574eeb0cf92a650bcdb4a8f7a4c8eafc2be87e8"
},
{
"source": ".local/contextual-prerelease-gui-20260911/package-delta-after-gui.json",
"path": "native/initial/package-delta-after-gui.json",
"bytes": 202,
"sha256": "94e2bde3a985a3b92329922bea35316298ed14c950b2a4d8f92435df3981b9f8"
},
{
"source": ".local/contextual-prerelease-gui-20260911/profile-desktop-correction.json",
"path": "native/initial/profile-desktop-correction.json",
"bytes": 270,
"sha256": "b566d6c03966ea834a523c962c365f181aa14c41bd44237dad80b6508f4aa981"
},
{
"source": ".local/contextual-prerelease-gui-20260911/profile-desktop-warning.jpg",
"path": "native/initial/profile-desktop-warning.jpg",
"bytes": 25684,
"sha256": "2994e5be5feb5a15eb6b561f23f03b1f7cc1b74beb013b59698c74a0ab5feb19"
},
{
"source": ".local/contextual-prerelease-gui-20260911/checkpoint-first/notes.arcadia",
"path": "native/initial/checkpoint-first/notes.arcadia",
"bytes": 63,
"sha256": "ad9de02963c20d1f43856455a797deb05ca674659e45f2c4b96b52783024f8bd"
},
{
"source": ".local/contextual-prerelease-gui-20260911/checkpoint-first/project.arcadia",
"path": "native/initial/checkpoint-first/project.arcadia",
"bytes": 860,
"sha256": "82297ccc2eae444f9ec7caca793ce71b2340904014289e36f8a6bc587f640f23"
},
{
"source": ".local/contextual-prerelease-gui-20260911/checkpoint-first/oa/activities/activity_assess_incident_work.arcadia",
"path": "native/initial/checkpoint-first/oa/activities/activity_assess_incident_work.arcadia",
"bytes": 142,
"sha256": "6fe331b65e7e9489221dd8914d26fa188d4941c1641685f5c24a4320cdb9c857"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/baseline.json",
"path": "native/v2/baseline.json",
"bytes": 428,
"sha256": "e549bfaea44b38145e5492483635e8b5d629cd9f9cd48d39b91cb870c68bc1ad"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/baseline.stderr.log",
"path": "native/v2/baseline.stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/baseline.stdout.log",
"path": "native/v2/baseline.stdout.log",
"bytes": 86,
"sha256": "738f111737ec2cda051e8830f96b4064faab072e5772ca63302a41cdf0c7b541"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/created-before-save.jpg",
"path": "native/v2/created-before-save.jpg",
"bytes": 116352,
"sha256": "d3e22341334722fde43583d8e38bbf49dd6a99dbdae39bc25d10ebc4f19c3e32"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/home.jpg",
"path": "native/v2/home.jpg",
"bytes": 98686,
"sha256": "2cfbc6e181429077787d3a6f629143b2dc62b28a3756ed7b19c8f8d59ab44068"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/launch.json",
"path": "native/v2/launch.json",
"bytes": 1521,
"sha256": "f82e8adb7f2c4a07dbbb33c0e8747a674f933a00e1affdeb5360ea1804b6b8e4"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/loaded-modules.json",
"path": "native/v2/loaded-modules.json",
"bytes": 13819,
"sha256": "62f9bba732f723169e4b3a7211a881b8f391273016c70acb8ad71a5d79ee9793"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/new-activity-ready.jpg",
"path": "native/v2/new-activity-ready.jpg",
"bytes": 115891,
"sha256": "67faf7cc8dfee72b9d1af447b5012c9fff0284b3091dca7911d4920d575c8589"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/normal-close.json",
"path": "native/v2/normal-close.json",
"bytes": 195,
"sha256": "a4bbd1cabe99303718b2dc77bbe06313c0e28a7802d6c76bb1c99806b476da08"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/offline-guide.jpg",
"path": "native/v2/offline-guide.jpg",
"bytes": 170754,
"sha256": "3a84f9f94d742c5fed47dbed6d53d0b122132b56e89251cc21c644fdfbb36118"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/package-before.json",
"path": "native/v2/package-before.json",
"bytes": 70373,
"sha256": "e604e6c0f4df3861241d7395a2d4be2d428c5870a7461b948628c23e90290e03"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/saved-model.jpg",
"path": "native/v2/saved-model.jpg",
"bytes": 116260,
"sha256": "5cdc7c28f73cf4bfdf639d16a5b55e7ea93df431af925bd5ef68ca8ad38d586a"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/staged-before-create.jpg",
"path": "native/v2/staged-before-create.jpg",
"bytes": 109910,
"sha256": "9ba81a18485b7df8ec9f872d0c3bceaff743cba486b579edcd9f1ec335773439"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/stderr.log",
"path": "native/v2/stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/stdout.log",
"path": "native/v2/stdout.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/package-after-close.json",
"path": "native/v2/package-after-close.json",
"bytes": 104,
"sha256": "d6641ee66a9732dc053c979ad4a378b07f8487b53ced87225e934ce6a18dd496"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/saved-files.json",
"path": "native/v2/saved-files.json",
"bytes": 304,
"sha256": "77f623114ff4c8774bddc9790f96256b26863e389a6407d6fbe8fd583c463cfb"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/saved.json",
"path": "native/v2/saved.json",
"bytes": 594,
"sha256": "254bcc0af17b50be4f0ee39a22e9993556de601a82191f826b8f2e4453c8762c"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/saved.stderr.log",
"path": "native/v2/saved.stderr.log",
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/saved.stdout.log",
"path": "native/v2/saved.stdout.log",
"bytes": 81,
"sha256": "ce1401a7002b272d197337c08574eeb0cf92a650bcdb4a8f7a4c8eafc2be87e8"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/checkpoint-first/notes.arcadia",
"path": "native/v2/checkpoint-first/notes.arcadia",
"bytes": 63,
"sha256": "ad9de02963c20d1f43856455a797deb05ca674659e45f2c4b96b52783024f8bd"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/checkpoint-first/project.arcadia",
"path": "native/v2/checkpoint-first/project.arcadia",
"bytes": 860,
"sha256": "b1fd5349f956f3a17005f883c6675c73aee0f6bcee2b9fa7a582996215c3b23e"
},
{
"source": ".local/contextual-prerelease-gui-20260911-v2/checkpoint-first/oa/activities/activity_assess_incident_work.arcadia",
"path": "native/v2/checkpoint-first/oa/activities/activity_assess_incident_work.arcadia",
"bytes": 142,
"sha256": "0bb8947810cf9a8bcb9394bf72ca512f9da5bf9128262188510367455291b1d7"
},
{
"source": ".local/contextual-prerelease-gui-20260911.py",
"path": "native/helpers/contextual-prerelease-gui-20260911.py",
"bytes": 5601,
"sha256": "951b1f4b913972c5c90b17e3e70f3644c4c9328d82372a325ee46debb345237a"
},
{
"source": ".local/contextual-prerelease-gui-v2-20260911.py",
"path": "native/helpers/contextual-prerelease-gui-v2-20260911.py",
"bytes": 6031,
"sha256": "9637ac8f5b9cd97ce672e0bd6b891454b2145a6236421d82536b8bdb2d66bc3c"
},
{
"source": ".local/contextual-prerelease-extraction2-20260911/preparation.json",
"path": "native/extraction2-preparation.json",
"bytes": 76980,
"sha256": "4b10a80dd0697061b52a75178d14ca0174cf3f66cbcad8cb281ae63bad2ea731"
},
{
"source": "harness/release-contextual-source-prerelease-gui-20260911.md",
"path": "native/report-before-v2.md",
"bytes": 4040,
"sha256": "19ec515d8d5e18f7c2e853dc34de2e01260eec891d190dc84877583ba42a5483"
}
],
"payloadFiles": 118,
"payloadBytes": 4913769,
"largeReferencedOriginalsNotDuplicated": [
{
"source": ".local/linux-qa/runtime/source7-20260907T082753190288Z.tar.gz",
"destination": "evidence/server-source-snapshot.tar.gz",
"sha256": "cbb371a93a562e1e641d7629fe351e016d63e66fc9112499b3fed6d5cd171f78",
"bytes": 2089801
},
{
"source": ".local/authoring-prerelease-20260911/packages/ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm/dependency-notices.json",
"destination": "evidence/prior-dependency-notices.json",
"sha256": "98fab15c1a2bb3aa727c6d52d5c69435b15efa56b6668ed717e7a04cf86f9b52",
"bytes": 1619590
}
],
"frozenReportsUnchanged": {
"harness/release-contextual-source-prerelease-preparation-20260911.md": "48fb5ecbef5d4bfbcff86fcf0c2770b2252a36b70da7272180b5ab3201c63c90",
"harness/release-contextual-source-prerelease-review-20260911.md": "fb95b410dc8fd0cef0d1a4b16d2efd6852c978aa47f8245a9b8c52c44e00ab4d"
},
"attributesBefore": "4b1bcac186548533eb38f3901badf456058eb7b9e6f5b974c397d52254435230"
}
@@ -0,0 +1,617 @@
{
"preparedUtc": "2026-09-11T16:34:53.482070+00:00",
"scope": "Preparation and exact extraction only; helper not executed, trial directory absent, no GUI/server/oracle/compiler/WSL launch or system change.",
"archive": {
"path": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-20260911\\packages\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm.zip",
"sha256": "9186d4fc9a7b52fb195c183c4847c8e3419ea6da8b3f907e0c06f9ceec58dee0",
"bytes": 32775691
},
"review": {
"path": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-review-20260911\\artifact-result.json",
"sha256": "3a6bf2580b25dad696d635dcbbde88522a065f83698229c2a22dda92f2ab6ee8",
"status": "PASS"
},
"package": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-extraction2-20260911\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm",
"files": {
"arcadia-server.exe": "efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665",
"arcadia-studio.exe": "5657bab5c841939b66f901efe6c0ffb2d7cbbe8cc5f111a0ca3de8073d3846ce",
"dependency-notices.json": "f318f87e6a23dcfac16ef7b1cfe51ecb804e98e1ff6a97271180319d5922fc0e",
"documentation-check.json": "bcc89585951fd9e5a1641993c51ca79e00a7a06944a8273d2df413331320e93f",
"libunwind.dll": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"package.json": "25f01823dbceed15468bf759eed3f9ffbfd1098427027288bcbb9a3d356b6a4d",
"README.md": "597cfb8da873e019d2658420f18ec059f0185fa9106ff9eafe934dfdd6ed266b",
"SHA256SUMS.txt": "04e4be3f6a081e11ccad8609643031d91fed82cd08e7c7821002ff9b9a04e454",
"START-HERE.txt": "a549295cf57ac73673dc4fa6106463450f982122793cb9c7135ce4fc7087e9ed",
"THIRD-PARTY-NOTICES.txt": "6756989c8fc73706641cd78449c315458425a2eed9a82febc289b9d28ea7f21f",
"deployment/arcadia-server.service": "1e6c6bb4065e25f8fe1d558a4ed0bbd4844782a4377c2482488db1e6f9cab01d",
"deployment/Dockerfile": "72c04aef4ec879955ed3bdf315987553d018ef46e4b8f350f0f6fe380c453eb7",
"deployment/Dockerfile.dockerignore": "6bb7d7496110b11a531cb8cd923864c6610850a8f1c4de8a797f54c7156f29e1",
"docs/api.html": "a06126cb741da57e9c06e83fc4137ccde0de05562673546bc9d405878f51ea07",
"docs/api.rst": "ca7d310138c3b4d429d80a1d03d1ac8d4a9296069e205da573034256d10438a7",
"docs/language.html": "67dcfa3477b48a0b07298ec81741840cc3ccff12c7d58164873d746d41d611c8",
"docs/language.rst": "ac6b1d982c55f246de2f3c844b24b874599a3c20cfbd7ed22efe4561ac622b83",
"docs/linux-packaging.md": "41a1bb1095801df37a1411341c5791d55ea8c365739314d599a60269ac4bc7a0",
"docs/openapi.json": "c6ae512f791a939eaf6ec5e5e78e9468bdee0e028092d00098bd90ad9498d967",
"docs/research-v2-service.md": "4828df5bc679e7c71f49b4b85c9e7dacbec52f46d416fed48af70e08886d4e4e",
"docs/server.md": "4eb24937d424ba8b384e1734e02a6f8e963ae11d2715889c92b14b39ff2e4a48",
"docs/windows-packaging.md": "2c852ff7041713ffbff3c951ac98df647c51fb70b0feba9000f7bfd5bc2703a8",
"examples/coastal-rescue.arcadia": "7e183ef9fd8154d3074303f1956cd0d9871c19e3ffc630d333b0bffbd6e30e17",
"examples/coastal-rescue.json": "242f0b031229a87af5c4ebe5d651defe59c191a6b7a69dc0a77f7e203411f195",
"examples/legacy-v1-coastal-rescue.arcadia": "4dbbbdf8bc7e6cb8e0a81dd678069dae585a9e5187c59bc3665e1fdab3f1a86a",
"examples/legacy-v1-coastal-rescue.oa.json": "fd0e9dedfb7adb922dc0575cc2b820d40344d639f1d8052bd70363aa59de9c24",
"examples/routing-workshop.arcadia": "dc6b75da72884d399132ed9e300fa5a26b73d802bb526c9af986ae9eeb0a646a",
"examples/routing-workshop.json": "8592714f75b271133f21ce017d87896b6cf91ea0e4837f1c2ed453e21be26b14",
"licenses/llvm-mingw-LICENSE.TXT": "8d85c1057d742e597985c7d4e6320b015a9139385cff4cbae06ffc0ebe89afee",
"examples/release1/expected-diagnostics.json": "3700393d76b940cfc076bf52861bd7b1f43370f8eabce3594531bd0bf1fc851e",
"examples/release1/model.json": "ef0ef4006c3e09d5db6e1b621256b3f7d6642f3a7b09cc34607cfbcca830c727",
"examples/release1/model.rs": "15f30f6bde655808fe754665c26d560e36f2a9bad340f346b09137d0d05045f5",
"examples/release1/project.arcadia": "b2674e6bf77cfe0f6f0ba79c81d2e96d92f39c02ca2c6266d80e91723bfb9fda",
"examples/release1/README.md": "113cfb1cf38a98b51bff60442d86a35d636a3d80ef206bece7d53d0aae67f2d5",
"examples/release1/traceability.arcadia": "48a96f543456c9b5a5798fc795594e4119147fe45f11a6f109f141b7f514560f",
"examples/release1/transition-before.json": "2253e6434f741687e22327c37d520ed15c043bc36025498650bc2366bb6a874d",
"examples/release1/transition-request.json": "43b9a22e5f95ad3bc0ebd2478ead0e14406854abc989ae94ded9367b013d812a",
"examples/source-project/oa.arcadia": "5f60642f211b2d352a951092faeeb7503d4fb7f6f7fca99e810347231101d31c",
"examples/source-project/project.arcadia": "787f6b67b179ffd221f7e5faf1a4edd74cfd116aa1e3b5e9ed9f22fbff612d8d",
"examples/source-project/views.arcadia": "e29ad3f406a6a50d2f0ae2ca2a53ee3b0c18222cd4098704a46d4f48b64ea17f",
"examples/text-first/project.arcadia": "f441535c623e0cf20e1875eb2cd33b587ed00e078c37af39cb36d89bb5edc19a",
"examples/text-first/README.md": "4ec8250d5ed556f1d496e8c85137e973e802ecb11df1a36488411e8cdc5a9f9e",
"examples/release1/evidence/repair-check.md": "f4db17bdca4ecbb1bf0caef01b2da5f1f7f798ab3152b648ce6dd8696a6a68e5",
"examples/release1/oa/capabilities.arcadia": "fc8012e5554350b12e1cb80080f8feab80d933c9b33c0f2a7bb500cb7d609936",
"examples/release1/oa/model.arcadia": "f7cf914766ea73ec53b85e32d117ea9a9dba52d3e038246863541ae7069b1a15",
"examples/release1/oa/participants.arcadia": "951764c14179f27c10e315acf2ea37d1fff54c77b8441e23addd239e8c715ce3",
"examples/release1/oa/types.arcadia": "9d0396fb82dd5733edd8d1cf52f968ca84906927c704f9cf0944a7fae215cf49",
"examples/release1/sa/capabilities.arcadia": "b6912fb3ece439912345fa71724acd462e716a1e5a88203a1058a5c3b2c20a4f",
"examples/release1/sa/model.arcadia": "d431509251acb859fbb98733b6d18add952495e10a78703fbe8f31e40bc083c4",
"examples/release1/sa/participants.arcadia": "780d2eb08b217b67b55febb3d34846f727b8ee9018df6c5741748647e36b2ff8",
"examples/release1/sa/types.arcadia": "101fc0fbd99f1101514aa7b6da4f8e535aae0bb94c9e2b9e7e6c151135b28660",
"examples/release1/views/diagram_oa_allocation_view.arcadia": "dfc0eb61e0e2aa5bda45524571fbfa3494f44ce19696f3e15e07438074a07bc7",
"examples/release1/views/diagram_sa_allocation_view.arcadia": "b78b43a26a82efb8fbd5374b09c329fa341f57b29f635d397b9ef8aede71d389",
"examples/release1/views/diagram_sa_capability_view.arcadia": "75e8dc9fb30f25d6f8fd3c6b595593ab4f98958a25798f961e336e0fac557649",
"examples/release1/views/diagram_sa_service_view.arcadia": "b08c84f3ea633e7c78dfdad3272f75415f6256cf3614b6d99bfd4f0269076c9b",
"examples/release1/views/diagram_sa_state_view.arcadia": "5f42f4c605e57b817d8400ed21f2b14bfc4e1592aebe941ff113767504c2b869",
"examples/release1/oa/activities/activity_oa_restore_work.arcadia": "83e73d0a013d5c3e1a4af0d9139ab0cfa362d25a846671fc2dac59181061a9d4",
"examples/release1/oa/behavior/process_oa_assessment_procedure.arcadia": "172c32c044ef4b5bc58a1f4635cc81f48dabb4014479b47dce7b25fedf2dbd0d",
"examples/release1/oa/behavior/process_oa_field_procedure.arcadia": "d2552dc5383e2e91cb302a790364e197f663c2edc013a2ab1978789825c9c324",
"examples/release1/oa/behavior/process_oa_response.arcadia": "cf86f46fa5c5d70592ef43f1bc1cb4d968efd8add384ba88036bef6b88aa4abc",
"examples/release1/oa/behavior/scenario_oa_conversation.arcadia": "b25be524e98a35ebac5e4481b7609c027b32baf9605e8097f807560f94a77ca6",
"examples/release1/oa/behavior/scenario_oa_full_scenario.arcadia": "00a1edf2c9707a0eb62ac070c2d02467874f2c9c1f273cc6ddb53d6d65999a1c",
"examples/release1/oa/behavior/state_machine_oa_monitor.arcadia": "447c9ad1359f4a31ecf975ad07c0b08d8e7e03191fb0858e2fc56f377b223cd5",
"examples/release1/sa/behavior/process_sa_assessment_procedure.arcadia": "73928ced61c06cbc08728d7956676a50fd4c05aa5b7f1ff4f29ce27a0b0f2088",
"examples/release1/sa/behavior/process_sa_field_procedure.arcadia": "886d462af83110cbfa55dd232a667ea1446761234471357cbb878794e98e8768",
"examples/release1/sa/behavior/process_sa_response.arcadia": "041785fc22842423822431bd5e6e8d16094ebd0716965e7c765fb8c1d7549e8a",
"examples/release1/sa/behavior/scenario_sa_conversation.arcadia": "97276f5757ee9aa12a0dbd9d3ccd58174b3091162bb8bcce357cec20a45f5d85",
"examples/release1/sa/behavior/scenario_sa_full_scenario.arcadia": "e12fc406b99d60a2f7768aaa0b25ba560e8605f0b8e37f3a7cdd3b8443562b74",
"examples/release1/sa/behavior/state_machine_sa_monitor.arcadia": "05ce29af99424c491c47fe2450dc6f5f8ce995511c01ec7e17bb5855be3c9736",
"examples/release1/sa/functions/function_sa_audit_thresholds.arcadia": "e5a04325d52183956dca814dd90f4e56c96c6b7db0f4f202f203ecb49c3e0f4f",
"examples/release1/sa/functions/function_sa_restore_work.arcadia": "fddeb67308051325041fee641fe758ddf43345b7c47b66d433616ad07fdccdd6",
"examples/source-project/sa/assurance.arcadia": "ab76044836e4dcd42a82d316846ec87da2108939aa2037640c5bca1d2ecdee0f",
"examples/source-project/sa/participants.arcadia": "1abad579812e77877b45a3d8e3c3e9da734be2d04a0254cc730a5257ebd2dc88",
"examples/source-project/sa/reporting.arcadia": "f0b7443f728912ca163de39b6055876b533a77feaa3219b2d40a2dd65712e058",
"licenses/llvm-libunwind/llvm-ea7d852a70e8-libunwind-LICENSE.TXT": "b5efebcaca80879234098e52d1725e6d9eb8fb96a19fce625d39184b705f7b6d",
"licenses/rust/COPYING.RUNTIME": "28e85c5aa4af9b4f1dfe6b4817aa3eefb3eaaee7fd735045016f29ccf50276a1",
"licenses/rust/COPYING3": "8ceb4b9ee5adedde47b31e975c1d90c73ad27b6b165a1dcd80c7c545eb65b903",
"licenses/rust/COPYRIGHT-library.html": "68129500b616d5838629e68f55ff3aed5e096dacf60ce9eb41bbe599a563afa6",
"licenses/rust/COPYRIGHT.html": "5b0c93fc4e6d4b072eaa521b1762d1e746f4c368f65e81a0e5308e2772dac85e",
"licenses/dependencies/arrayref-0.3.9/LICENSE": "1bc7e6f475b3ec99b7e2643411950ae2368c250dd4c5c325f80f9811362a94a1",
"licenses/dependencies/arrayvec-0.7.8/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/arrayvec-0.7.8/LICENSE-MIT": "4da95ec4ecb65b738d470b7d762894ad9c97da93e6cbfb18b570fc2c96f4b871",
"licenses/dependencies/ash-0.38.0+1.3.281/LICENSE-APACHE": "0e8a410375e1ee5c75c6198b08b534fec6e5edef766cf971bab4a404542636ab",
"licenses/dependencies/ash-0.38.0+1.3.281/LICENSE-MIT": "c733ccf8ab25df175a63d9d844677b98e3a5ab8f8de1c1616087e6868a7f948e",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-THIRD-PARTY": "6226d0632e2e1a80c23597e964da9812ae193c535fe058154afb034e94167aa5",
"licenses/dependencies/autocfg-1.5.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/autocfg-1.5.1/LICENSE-MIT": "27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac",
"licenses/dependencies/axum-0.8.9/LICENSE": "6a13bc24a100a6812f053879ec51b126b103af7cda6dbf48c4188722da44da9f",
"licenses/dependencies/axum-core-0.5.6/LICENSE": "008c87afcd2e626eaf564093250bed06dd7efb5732113264bba3dda8f1c556a1",
"licenses/dependencies/base64-0.22.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/base64-0.22.1/LICENSE-MIT": "0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7",
"licenses/dependencies/bit-set-0.8.0/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/bit-set-0.8.0/LICENSE-MIT": "f51ac2c59a222f7476ce507ca879960e2b64ea64bb2786eefdbeb7b0b538d1b7",
"licenses/dependencies/bit-vec-0.8.0/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/bit-vec-0.8.0/LICENSE-MIT": "f51ac2c59a222f7476ce507ca879960e2b64ea64bb2786eefdbeb7b0b538d1b7",
"licenses/dependencies/bitflags-2.13.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/bitflags-2.13.1/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-APACHE": "e3ba223bb1423f0aad8c3dfce0fe3148db48926d41e6fbc3afbbf5ff9e1c89cb",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-MIT": "9df9ba60a11af705f2e451b53762686e615d86f76b169cf075c3237730dbd7e2",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-ZLIB": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-APACHE": "e3ba223bb1423f0aad8c3dfce0fe3148db48926d41e6fbc3afbbf5ff9e1c89cb",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-MIT": "9df9ba60a11af705f2e451b53762686e615d86f76b169cf075c3237730dbd7e2",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-ZLIB": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/bytes-1.12.1/LICENSE": "45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42",
"licenses/dependencies/cc-1.4.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cc-1.4.5/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/cfg-if-1.0.4/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cfg-if-1.0.4/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/cfg_aliases-0.2.2/LICENSE": "31b94860253d8ec7b4529f51901044d3b459d6292d996504a36b1bae3a36a812",
"licenses/dependencies/chacha20-0.10.2/LICENSE-APACHE": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
"licenses/dependencies/chacha20-0.10.2/LICENSE-MIT": "b8c6939380a400f53e11923d50fcc4dd2fa1ba8339fd9d04cda38a0251b6c9b0",
"licenses/dependencies/codespan-reporting-0.12.0/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/core_maths-0.1.1/LICENSE": "9ebf8c4cc0b735ca13a766451f7b8097db3185975ceb2ba94b5abf439156a91f",
"licenses/dependencies/cosmic-text-0.15.0/LICENSE-APACHE": "000b4962e6b27176a0ff89cce4be555b16472cafb5671eb2804a8fdac6854793",
"licenses/dependencies/cosmic-text-0.15.0/LICENSE-MIT": "95557bafe728379e206f3b6d4aceeaa054d271c71d722411a6222e2dec01138c",
"licenses/dependencies/cpufeatures-0.3.1/LICENSE-APACHE": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
"licenses/dependencies/cpufeatures-0.3.1/LICENSE-MIT": "73b9dc2e79c7308998dd30296e073aefaefb944a68fb89aa412c23c0edcabcaa",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-ZLIB": "b3ec01ad0869c5c50937bc68780cd0bb44e235ad858dfa54a7a381dced9b115a",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-APACHE": "b59affd015e517ed998dd735757f9a3693643cd389609947ed54074234a10784",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-MIT": "c138726a726ac37bae09d0f8a48e74e8e3aa8a8952fcd10fae0fb224cc1c05f1",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-ZLIB": "01e533bd94e8f1c32b2c2531e2c398de7d35d7804add3d574b4e1fe581d53537",
"licenses/dependencies/displaydoc-0.2.7/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/displaydoc-0.2.7/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/document-features-0.2.12/LICENSE-APACHE": "074e6e32c86a4c0ef8b3ed25b721ca23aca83df277cd88106ef7177c354615ff",
"licenses/dependencies/document-features-0.2.12/LICENSE-MIT": "aa893340d14b9844625be6a50ac644169a01b52f0211cbf81b09e1874c8cd81d",
"licenses/dependencies/dpi-0.1.2/LICENSE": "6dc0e068dcf3a5bc8e054205b85b7720e1d49265bbc64bf515d2cf79197df69a",
"licenses/dependencies/dpi-0.1.2/LICENSE-LIBM-MIT": "9eff396a99bafd208e7126602420d6864f6066c08b84485a5b032320a9c01997",
"licenses/dependencies/equivalent-1.0.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/equivalent-1.0.2/LICENSE-MIT": "7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349",
"licenses/dependencies/error-code-3.4.0/LICENSE": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/etagere-0.2.15/LICENSE-APACHE": "2d56a37f3d1e461f6b1539ab94e0e6bcc55443e376098aee85ac3b2890860290",
"licenses/dependencies/etagere-0.2.15/LICENSE-MIT": "9cfc9c9a4608501b5da3746948d2be2dd709ad51f6bcb0c1c685760ee3dde31f",
"licenses/dependencies/euclid-0.22.14/COPYRIGHT": "ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a",
"licenses/dependencies/euclid-0.22.14/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/euclid-0.22.14/LICENSE-MIT": "62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3",
"licenses/dependencies/fastrand-2.5.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/fastrand-2.5.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/find-msvc-tools-0.1.12/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/find-msvc-tools-0.1.12/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/float_next_after-1.0.0/LICENSE": "0604d5817110dacc5c7d9b7de6b58b962794603d4823c357157bd5dec4198bc5",
"licenses/dependencies/foldhash-0.1.5/LICENSE": "b1181a40b2a7b25cf66fd01481713bc1005df082c53ef73e851e55071b102744",
"licenses/dependencies/foldhash-0.2.0/LICENSE": "b1181a40b2a7b25cf66fd01481713bc1005df082c53ef73e851e55071b102744",
"licenses/dependencies/font-types-0.10.1/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/font-types-0.10.1/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/font-types-0.12.4/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/font-types-0.12.4/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/fontdb-0.23.0/LICENSE": "59a1fdac3bd550043599bd159fd70f09a1108c2b09e3751d39b11e1ff8e51f00",
"licenses/dependencies/form_urlencoded-1.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/form_urlencoded-1.2.2/LICENSE-MIT": "20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e",
"licenses/dependencies/futures-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-channel-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-channel-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-core-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-core-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-executor-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-executor-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-io-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-io-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-macro-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-macro-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-sink-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-sink-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-task-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-task-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-util-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-util-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/getrandom-0.2.17/LICENSE-APACHE": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
"licenses/dependencies/getrandom-0.2.17/LICENSE-MIT": "42fa16951ce7f24b5a467a40e5b449a1d41e662f97ca779864f053f39e097737",
"licenses/dependencies/getrandom-0.4.3/LICENSE-APACHE": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
"licenses/dependencies/getrandom-0.4.3/LICENSE-MIT": "523a42c25d245dde9c015f882cec7f4555aad883382a6cf19b4b7d9b2cd5419b",
"licenses/dependencies/glam-0.25.0/LICENSE-APACHE": "be33ddb87a30fd321ab100e2d922cba512e50ec7a63d8e62e5bfc0798dd4b585",
"licenses/dependencies/glam-0.25.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/glow-0.16.0/LICENSE-APACHE": "b8601fc79bdf8d8088f0938bea861ffc63ed0eebbedf25f44ab2cf2e85bd7edc",
"licenses/dependencies/glow-0.16.0/LICENSE-MIT": "cdbd06e25b8c9c5d6019949d2de8123f56d29cee4166396423d2ba8c81700845",
"licenses/dependencies/glow-0.16.0/LICENSE-ZLIB": "636f644f1e149eb62961657c0e34953681eff64435653912e7bd19992666faa5",
"licenses/dependencies/glutin_wgl_sys-0.6.1/LICENSE": "a4445427440043e8ce6fadf7a43fb906cb0d7f6c573a560a9f142cf9f9bf8ff4",
"licenses/dependencies/gpu-allocator-0.27.0/LICENSE-APACHE": "0178e21322b0e88aa3aeb3146f6a9611bc1f8df6d98bdfb34be28b9dd56a8107",
"licenses/dependencies/gpu-allocator-0.27.0/LICENSE-MIT": "ad41be6cc6538b29b9346648f41432b5e460bad6be073b5eeaa41320ea2921dc",
"licenses/dependencies/guillotiere-0.6.2/LICENSE": "7e98bed7f100747aaae7d82ab94fbe6b76fd6b84b09a3aaa413bff8196d0fbb1",
"licenses/dependencies/half-2.7.1/LICENSE-APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/half-2.7.1/LICENSE-MIT": "508a77d2e7b51d98adeed32648ad124b7b30241a8e70b2e72c99f92d8e5874d1",
"licenses/dependencies/harfrust-0.3.2/LICENSE": "7d43d2ef1ce976c7bfb423c696ad9938ccfc31e9ec5be752265e43fe9d29f697",
"licenses/dependencies/hashbrown-0.15.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.15.5/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/hashbrown-0.16.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.16.1/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/hashbrown-0.17.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.17.1/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/http-1.5.0/LICENSE-APACHE": "8bb1b50b0e5c9399ae33bd35fab2769010fa6c14e8860c729a52295d84896b7a",
"licenses/dependencies/http-1.5.0/LICENSE-MIT": "dc91f8200e4b2a1f9261035d4c18c33c246911a6c0f7b543d75347e61b249cff",
"licenses/dependencies/http-body-1.1.0/LICENSE": "248378d0a3383c173fb925f17141b88e71580b3ba17ddc6ac3d2a344683232ab",
"licenses/dependencies/http-body-util-0.1.5/LICENSE": "248378d0a3383c173fb925f17141b88e71580b3ba17ddc6ac3d2a344683232ab",
"licenses/dependencies/httparse-1.10.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/httparse-1.10.1/LICENSE-MIT": "391a5396cec6230bfabd4ef4eb2350eb895bc5efce377a2218f5702ed020d3e3",
"licenses/dependencies/httpdate-1.0.3/LICENSE-APACHE": "4d10fe5f3aa176b05b229a248866bad70b834c173f1252a814ff4748d8a13837",
"licenses/dependencies/httpdate-1.0.3/LICENSE-MIT": "934887691e05d69d7c86ad3f2c360980fa30c15b035e351f3c9865e99da4debc",
"licenses/dependencies/hyper-1.11.1/LICENSE": "2d01890414494742ba4a509fcec8efa40f6d8be22cbd72be7cff08d6fda4ec89",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-ISC": "7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-MIT": "709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c",
"licenses/dependencies/hyper-util-0.1.20/LICENSE": "9e0a97848ea543aef745c98e84fde696a9a3e0735538f6daefdd3cb1942effc1",
"licenses/dependencies/iced-0.14.0/LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/icu_collections-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_locale_core-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_normalizer-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_normalizer_data-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_properties-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_properties_data-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_provider-2.3.1/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/idna-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/idna-1.1.0/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/idna_adapter-1.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/idna_adapter-1.2.2/LICENSE-MIT": "8b43ce8accd61e9d370b5ca9e9c4f953279b5c239926c62315b40e24df51b726",
"licenses/dependencies/indexmap-2.14.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/indexmap-2.14.1/LICENSE-MIT": "ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055",
"licenses/dependencies/ipnet-2.12.1/LICENSE-APACHE": "87d9feb9238c6bd8e0024fc4733b06cff036f89f36d93b7df1c8a0549bbb7a5b",
"licenses/dependencies/ipnet-2.12.1/LICENSE-MIT": "47dc9ff29128ddfb4d6a0435383c9f89120bc374dbcc1dd00b933a0b28aa7865",
"licenses/dependencies/itoa-1.0.18/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/itoa-1.0.18/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/jobserver-0.1.35/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/jobserver-0.1.35/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/khronos-egl-6.0.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/khronos-egl-6.0.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/kurbo-0.10.4/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/kurbo-0.10.4/LICENSE-MIT": "23c23145f6eac25c28cdcc03d38506a5712a9a8cffb5bd5301457f6173ea696e",
"licenses/dependencies/libc-0.2.189/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/libc-0.2.189/LICENSE-MIT": "123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e",
"licenses/dependencies/libloading-0.8.9/LICENSE": "b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f",
"licenses/dependencies/libm-0.2.16/LICENSE.txt": "3823dda7cf046602f4b4e77ec8e227863dc4736037cc85bb33d9f19febe16bb7",
"licenses/dependencies/lilt-0.8.2/LICENSE": "120b2f21f9b9f98ef4159de09f9a55a3afb6733dd1c0b1d9eeec7f136465b2cd",
"licenses/dependencies/linebender_resource_handle-0.1.1/LICENSE-APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/linebender_resource_handle-0.1.1/LICENSE-MIT": "508a77d2e7b51d98adeed32648ad124b7b30241a8e70b2e72c99f92d8e5874d1",
"licenses/dependencies/litemap-0.8.3/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/litrs-1.0.0/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/litrs-1.0.0/LICENSE-MIT": "7dc1552e88f49132cb358b1b962fc5e79fa42d70bcbb88c526d33e45b8e98036",
"licenses/dependencies/lock_api-0.4.14/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/lock_api-0.4.14/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/log-0.4.34/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/log-0.4.34/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/lru-0.16.4/LICENSE": "061dc50af2cd9340703daf61978af3200cf681b12ea67a323c33ba109a23a45e",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-MIT": "1466d9b4f3a59bb8997fc8d5fa977ce3f6a24bb2358793c09bfdf007039f6486",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-ZLIB": "09785877275ffada6c371b652a30e95c26b435126fc0fc62f1bc2d72171f80a4",
"licenses/dependencies/matchit-0.8.4/LICENSE": "de701d0618d694feb1af90f02181a1763d9b0bdeb70a3a592781e529077dba65",
"licenses/dependencies/matchit-0.8.4/LICENSE.httprouter": "162ce11ad71338d0a0c6ebaf5c48af72c6ae237b468859d3656fe2d9ed3f3a85",
"licenses/dependencies/memchr-2.8.3/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/memchr-2.8.3/LICENSE-MIT": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
"licenses/dependencies/memchr-2.8.3/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/memmap2-0.9.11/LICENSE-APACHE": "04ea4849dba9dcae07113850c6f1b1a69052c625210639914eee352023f750ad",
"licenses/dependencies/memmap2-0.9.11/LICENSE-MIT": "0d25d03b5ab49576178ad0cae7a2648d12c17ad0452fe49c07e55e4b59aa5257",
"licenses/dependencies/mime-0.3.17/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/mime-0.3.17/LICENSE-MIT": "df9cfd06d8a44d9a671eadd39ffd97f166481da015a30f45dfd27886209c5922",
"licenses/dependencies/mio-1.2.3/LICENSE": "07919255c7e04793d8ea760d6c2ce32d19f9ff02bdbdde3ce90b1e1880929a9b",
"licenses/dependencies/naga-27.0.3/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/naga-27.0.3/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/num-traits-0.2.19/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/num-traits-0.2.19/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/oa-core-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/oa-desktop-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/oa-server-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/once_cell-1.21.4/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/once_cell-1.21.4/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/ordered-float-5.5.0/LICENSE-MIT": "f7715d38a3fa1b4ac97c5729740752505a39cb92ee83ab5b102aeb5eaa7cdea4",
"licenses/dependencies/parking_lot-0.12.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/parking_lot-0.12.5/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/parking_lot_core-0.9.12/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/parking_lot_core-0.9.12/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/percent-encoding-2.3.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/percent-encoding-2.3.2/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/pin-project-lite-0.2.17/LICENSE-APACHE": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/pin-project-lite-0.2.17/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/pkg-config-0.3.34/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/pkg-config-0.3.34/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/potential_utf-0.1.6/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/presser-0.3.1/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/presser-0.3.1/LICENSE-MIT": "090a294a492ab2f41388252312a65cf2f0e423330b721a68c6665ac64766753b",
"licenses/dependencies/proc-macro2-1.0.107/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/proc-macro2-1.0.107/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/quinn-0.11.11/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-0.11.11/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quinn-proto-0.11.17/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-proto-0.11.17/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quinn-udp-0.5.15/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-udp-0.5.15/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quote-1.0.47/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/quote-1.0.47/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/rand-0.10.2/COPYRIGHT": "90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5",
"licenses/dependencies/rand-0.10.2/LICENSE-APACHE": "35242e7a83f69875e6edeff02291e688c97caafe2f8902e4e19b49d3e78b4cab",
"licenses/dependencies/rand-0.10.2/LICENSE-MIT": "209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b",
"licenses/dependencies/rand_core-0.10.1/COPYRIGHT": "92b81db30f7ab6d693e0af5661a40d273ca1947e891123ed823924192c10cbc7",
"licenses/dependencies/rand_core-0.10.1/LICENSE-APACHE": "6df43f6f4b5d4587f3d8d71e45532c688fd168afa5fe89d571cb32fa09c4ef51",
"licenses/dependencies/rand_core-0.10.1/LICENSE-MIT": "8b6e9feec03e7c9a5facb26855cecd31662bf989b636bcfe79521bdf8ac863f0",
"licenses/dependencies/rand_pcg-0.10.2/COPYRIGHT": "90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5",
"licenses/dependencies/rand_pcg-0.10.2/LICENSE-APACHE": "6df43f6f4b5d4587f3d8d71e45532c688fd168afa5fe89d571cb32fa09c4ef51",
"licenses/dependencies/rand_pcg-0.10.2/LICENSE-MIT": "2234e3cefee876aeb686ad89e978bdb07bf118a1186ab1cf161bcdf69d4b4f57",
"licenses/dependencies/range-alloc-0.1.5/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/range-alloc-0.1.5/LICENSE.MIT": "ba00052102ed87948bb8822d6e1c496260c83042887b22bb5caad922ec025a60",
"licenses/dependencies/rangemap-1.8.0/LICENSE-APACHE": "1c7745cc26c7294bc9dbc883bcd50700b99a8c0f4859bfce84ec555098ce1ab5",
"licenses/dependencies/rangemap-1.8.0/LICENSE-MIT": "29a4c3823ee29ee5a97c145574a1bac20629fd5e6708be1df0d25bab563e093c",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-APACHE.md": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-MIT.md": "9c5a80639a57c1c945570e7ebbca0706305849ce3c098021325cca9db2f7acc4",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-ZLIB.md": "ae895c8576e682f310fb70d93d9f99b1dd82872094c54a8f6cdfe2ca5c2d6ecb",
"licenses/dependencies/read-fonts-0.35.0/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/read-fonts-0.35.0/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/read-fonts-0.41.0/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/read-fonts-0.41.0/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/renderdoc-sys-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/renderdoc-sys-1.1.0/LICENSE-MIT": "24b2f2eff5a7622e87162823e260f00c6dfbce0e26d585d3d28c785f1edc80ed",
"licenses/dependencies/reqwest-0.12.28/LICENSE-APACHE": "751963a8b88c0e3a9f27e98933079fbcf09b9998b2c13ac49c2e4d58444520d6",
"licenses/dependencies/reqwest-0.12.28/LICENSE-MIT": "47d4e1803702728e03d30f8a848ae2249ba274bbd9f8443e803f7924d83cd371",
"licenses/dependencies/rfd-0.15.4/LICENSE": "65fc947f4bac882a2cd104ef73c246b1b037059df9f2b3a58b7f77f0b9e56071",
"licenses/dependencies/ring-0.17.14/LICENSE": "b3d734001a94efff3579978d953391aa7115f877657d25eb54037a43875d078a",
"licenses/dependencies/ring-0.17.14/LICENSE-BoringSSL": "005fc765ddc5115da796cca915baa9557abae13ff35e0a47c47affc56f6c414d",
"licenses/dependencies/ring-0.17.14/LICENSE-other-bits": "f025ccfb7dfb6bdfedc75ca0f67acc69e6fb4998143d834f7c2f38a29989680f",
"licenses/dependencies/rustc-hash-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/rustc-hash-1.1.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/rustc-hash-2.1.3/LICENSE-APACHE": "95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc",
"licenses/dependencies/rustc-hash-2.1.3/LICENSE-MIT": "30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652",
"licenses/dependencies/rustls-0.23.43/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/rustls-0.23.43/LICENSE-ISC": "7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4",
"licenses/dependencies/rustls-0.23.43/LICENSE-MIT": "709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c",
"licenses/dependencies/rustls-pki-types-1.15.1/LICENSE-APACHE": "45fd05c4865e7c350b98ad7ac50e1b15462d49af4a91e9b0c9dd933dc9a69742",
"licenses/dependencies/rustls-pki-types-1.15.1/LICENSE-MIT": "9117d922e667125508dde62b02c1f57ed22f5ad21eb536aa2e2d99e1c796e639",
"licenses/dependencies/rustls-webpki-0.103.15/LICENSE": "5b698ca13897be3afdb7174256fa1574f8c6892b8bea1a66dd6469d3fe27885a",
"licenses/dependencies/ryu-1.0.23/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/ryu-1.0.23/LICENSE-BOOST": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/same-file-1.0.6/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/same-file-1.0.6/LICENSE-MIT": "cb3c929a05e6cbc9de9ab06a4c57eeb60ca8c724bef6c138c87d3a577e27aa14",
"licenses/dependencies/same-file-1.0.6/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/scopeguard-1.2.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/scopeguard-1.2.0/LICENSE-MIT": "fb77f0a9c53e473abe5103c8632ef9f0f2874d4fb3f17cb2d8c661aab9cee9d7",
"licenses/dependencies/self_cell-1.3.0/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/self_cell-1.3.0/LICENSE-GPLv2": "f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505",
"licenses/dependencies/serde-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_core-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_core-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_derive-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_derive-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_json-1.0.151/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_json-1.0.151/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_path_to_error-0.1.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_path_to_error-0.1.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_urlencoded-0.7.1/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_urlencoded-0.7.1/LICENSE-MIT": "b9eb266294324f672cbe945fe8f2e32f85024f0d61a1a7d14382cdde0ac44769",
"licenses/dependencies/sha1_smol-1.0.1/LICENSE": "282a21b0710441c364025461a447362daf18f5798a7b72ae2f801a2aa536da51",
"licenses/dependencies/shlex-2.0.1/LICENSE-APACHE": "553fffcd9b1cb158bc3e9edc35da85ca5c3b3d7d2e61c883ebcfa8a65814b583",
"licenses/dependencies/shlex-2.0.1/LICENSE-MIT": "4455bf75a91154108304cb283e0fea9948c14f13e20d60887cf2552449dea3b1",
"licenses/dependencies/skrifa-0.37.0/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/skrifa-0.37.0/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/skrifa-0.44.0/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/skrifa-0.44.0/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/slab-0.4.12/LICENSE": "8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18",
"licenses/dependencies/slotmap-1.1.1/LICENSE": "6cec81441b2ab2b5090954c1fb5d0bcca81b86487b5849061fa8952d20ef67d4",
"licenses/dependencies/smallvec-1.16.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/smallvec-1.16.0/LICENSE-MIT": "0b28172679e0009b655da42797c03fd163a3379d5cfa67ba1f1655e974a2a1a9",
"licenses/dependencies/smol_str-0.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/smol_str-0.2.2/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/socket2-0.6.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/socket2-0.6.5/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/softbuffer-0.4.8/LICENSE-APACHE": "a4445427440043e8ce6fadf7a43fb906cb0d7f6c573a560a9f142cf9f9bf8ff4",
"licenses/dependencies/softbuffer-0.4.8/LICENSE-MIT": "0463bfa47d6d763d8c824333efb0e6d6df3946c13c3b077c78ed9f23ca50d0f2",
"licenses/dependencies/stable_deref_trait-1.2.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/stable_deref_trait-1.2.1/LICENSE-MIT": "5e05b024f653a5ce199e77cbbbd42fb5553562ec714b819421ed0c3e552a75d7",
"licenses/dependencies/static_assertions-1.1.0/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/static_assertions-1.1.0/LICENSE-MIT": "ea084a2373ebc1f0902c09266e7bf25a05ab3814c1805bb017ffa7308f90c061",
"licenses/dependencies/strict-num-0.1.1/LICENSE": "3085885678bb161f6c472bbd331f66a2550b555eb76128f7f8247779128199c0",
"licenses/dependencies/subtle-2.6.1/LICENSE": "d1fc1bc0d155df60b2e7705b6b2ae02a05c96f948e1cec6e2fb86360b09f346b",
"licenses/dependencies/swash-0.2.10/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/swash-0.2.10/LICENSE-MIT": "122dadfc2eb4de0f4bafcd9eb4e7502cfe338a7965ebd1d18708cc5050f43f76",
"licenses/dependencies/syn-2.0.119/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/syn-2.0.119/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/syn-3.0.5/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/syn-3.0.5/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/sync_wrapper-1.0.2/LICENSE": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/synstructure-0.13.2/LICENSE": "219920e865eee70b7dcfc948a86b099e7f4fe2de01bcca2ca9a20c0a033f2b59",
"licenses/dependencies/sys-locale-0.3.2/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/sys-locale-0.3.2/LICENSE-MIT": "5cc390ab5e5e6507f467368cbab1297552d64bfd863f4b496c7928508bcfefd8",
"licenses/dependencies/tempfile-3.27.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/tempfile-3.27.0/LICENSE-MIT": "8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36",
"licenses/dependencies/termcolor-1.4.1/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/termcolor-1.4.1/LICENSE-MIT": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
"licenses/dependencies/termcolor-1.4.1/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/thiserror-1.0.69/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-1.0.69/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-2.0.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-2.0.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-impl-1.0.69/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-impl-1.0.69/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-impl-2.0.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-impl-2.0.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/tiny-skia-0.11.4/LICENSE": "6d41e05f1d54fe726997cb0334ec539f1dff50600b1d5d90462ec2b392770ced",
"licenses/dependencies/tiny-skia-path-0.11.4/LICENSE": "6d41e05f1d54fe726997cb0334ec539f1dff50600b1d5d90462ec2b392770ced",
"licenses/dependencies/tinystr-0.8.4/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-APACHE.md": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-MIT.md": "fd80a26fbb3f644af1fa994134446702932968519797227e07a1368dea80f0bc",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-ZLIB.md": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-APACHE.md": "4f44572785f35152c1fd2eadf565b7e079c0f300b4324f0af653419f9d76b735",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-MIT.md": "1dd8eca0f83669e75fa119e34fb9e1be9d16e3e9b6368962b8019db6e8ae5f7b",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-ZLIB.md": "41ace205715d9f19a3214218cc1c01d57c533e02cd0fef7c8e51a49a7fce5ac5",
"licenses/dependencies/tokio-1.53.1/LICENSE": "253cd04c6714889df2d32f3f64d669179a1c95c76ac43c40882c52eb06bc3552",
"licenses/dependencies/tokio-macros-2.7.2/LICENSE": "0b83dc40cba89b9922bb84b0a9c7d2768ce37c1d7e138b7424fd4549915778c9",
"licenses/dependencies/tokio-rustls-0.26.5/LICENSE-APACHE": "cc117d90b498b32b11a886f279b359da16a73c3b01efbb2f5cc004b20262334e",
"licenses/dependencies/tokio-rustls-0.26.5/LICENSE-MIT": "e20fa2b8e0a2565f24a792b94b4bf4b6c2b9d36f781d8a9516e218a036e6677a",
"licenses/dependencies/tower-0.5.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tower-http-0.6.11/LICENSE": "5049cf464977eff4b4fcfa7988d84e74116956a3eb9d5f1d451b3f828f945233",
"licenses/dependencies/tower-layer-0.3.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tower-service-0.3.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tracing-0.1.44/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/tracing-attributes-0.1.31/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/tracing-core-0.1.36/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/try-lock-0.2.5/LICENSE": "c816a0749cdc6bf062a5111c159723de51b2bfac66a1dac2655abd9e6b1583eb",
"licenses/dependencies/ttf-parser-0.25.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/ttf-parser-0.25.1/LICENSE-MIT": "f3c9fe731c701ed77fd5fbaac573872af04dc5869385eb9bd5e3c73c42713814",
"licenses/dependencies/unicode-bidi-0.3.18/COPYRIGHT": "edb20b474f6cbd4f4db066b54a9e0f687d0009d309412a63431189b59b8e2a07",
"licenses/dependencies/unicode-bidi-0.3.18/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-bidi-0.3.18/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-UNICODE": "f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1",
"licenses/dependencies/unicode-linebreak-0.1.5/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/unicode-script-0.5.8/LICENSE-APACHE": "7cbb56d1b5d83d735056b363ab20958524120afafc4ad8206e6be98cdec5d737",
"licenses/dependencies/unicode-script-0.5.8/LICENSE-MIT": "7ad3ea8ca3caf894db98c3f31d5d4949173ffa93c883ef19a9e529ad48960f8c",
"licenses/dependencies/unicode-segmentation-1.13.3/COPYRIGHT": "23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d",
"licenses/dependencies/unicode-segmentation-1.13.3/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-segmentation-1.13.3/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/unicode-width-0.2.2/COPYRIGHT": "23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d",
"licenses/dependencies/unicode-width-0.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-width-0.2.2/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/untrusted-0.9.0/LICENSE.txt": "7abd9b6960dcf7d4d0a48606a5b71bfe37d472db68d70637f3a58a56785f1621",
"licenses/dependencies/url-2.5.8/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/url-2.5.8/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/utf8_iter-1.0.4/COPYRIGHT": "c30152c94a6d75e021adbc52b3a52470366a46edb917e17deae3259251af244c",
"licenses/dependencies/utf8_iter-1.0.4/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/utf8_iter-1.0.4/LICENSE-MIT": "3fa4ca83dcc9237839b1bdeb2e6d16bdfb5ec0c5ce42b24694d8bbf0dcbef72c",
"licenses/dependencies/uuid-1.26.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/uuid-1.26.0/LICENSE-MIT": "436bc5a105d8e57dcd8778730f3754f7bf39c14d2f530e4cde4bd2d17a83ec3d",
"licenses/dependencies/version_check-0.9.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/version_check-0.9.5/LICENSE-MIT": "b7e650f3fce5c53249d1cdc608b54df156a97edd636cf9d23498d0cfe7aec63e",
"licenses/dependencies/want-0.3.1/LICENSE": "a65f5d0a945d267751344c95665945b90c030ea107faf5c85d518929886187da",
"licenses/dependencies/web-time-1.1.0/LICENSE-APACHE": "54a744942eb3fa63a74d8d359989ed6962c04f3f10ff20cfa08ff8aa7efbe4e6",
"licenses/dependencies/web-time-1.1.0/LICENSE-MIT": "f428305bbf2e70fbd807af0f3c7ac1b7acfb95311640f451e9d2e48db6d7e96b",
"licenses/dependencies/webpki-roots-1.0.9/LICENSE": "e271993808fec50ab29350b39539cdec611a9103f827e0aa26d61da70e2d33f8",
"licenses/dependencies/wgpu-27.0.1/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-27.0.1/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-core-27.0.3/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-core-27.0.3/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-core-deps-windows-linux-android-27.0.0/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-core-deps-windows-linux-android-27.0.0/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-hal-27.0.4/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-hal-27.0.4/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-types-27.0.1/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-types-27.0.1/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/winapi-util-0.1.11/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/winapi-util-0.1.11/LICENSE-MIT": "cb3c929a05e6cbc9de9ab06a4c57eeb60ca8c724bef6c138c87d3a577e27aa14",
"licenses/dependencies/winapi-util-0.1.11/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/windows-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-core-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-core-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-implement-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-implement-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-interface-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-interface-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-link-0.2.1/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-link-0.2.1/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-result-0.2.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-result-0.2.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-strings-0.1.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-strings-0.1.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.52.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.52.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.59.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.59.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.61.2/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.61.2/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-targets-0.52.6/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-targets-0.52.6/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows_x86_64_gnullvm-0.52.6/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows_x86_64_gnullvm-0.52.6/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/window_clipboard-0.5.1/LICENSE": "7faec985f3e9b1c4a1df646bfedc304ba67e409447f7ab7f4f591f68708d85dc",
"licenses/dependencies/winit-0.30.13/LICENSE": "6dc0e068dcf3a5bc8e054205b85b7720e1d49265bbc64bf515d2cf79197df69a",
"licenses/dependencies/writeable-0.6.4/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/xml-rs-0.8.29/LICENSE": "0dc18d924dc0a5f41172a393012843a5eaaef338e795b3645da9cc3b6068220b",
"licenses/dependencies/yazi-0.2.1/LICENSE-APACHE": "7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c",
"licenses/dependencies/yazi-0.2.1/LICENSE-MIT": "df62e3ef3f207c91073fedd78b4156a278681d0dd3f942379242c62c6a71a3ec",
"licenses/dependencies/yoke-0.8.3/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/yoke-derive-0.8.2/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zeno-0.3.3/LICENSE-APACHE": "7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c",
"licenses/dependencies/zeno-0.3.3/LICENSE-MIT": "34dff8202d63e6df022f4f0ce88dab24f254c35ee0d5958b74dcf74d9eae21cc",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-APACHE": "9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-BSD": "83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-MIT": "1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-APACHE": "9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-BSD": "83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-MIT": "1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df",
"licenses/dependencies/zerofrom-0.1.8/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerofrom-derive-0.1.7/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zeroize-1.9.0/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/zeroize-1.9.0/LICENSE-MIT": "8c7516d4b27b1e495be5e38b612298b63de48d05f49cdac94f70f3cd70f8864b",
"licenses/dependencies/zerotrie-0.2.5/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerovec-0.11.8/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerovec-derive-0.11.6/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zmij-1.0.23/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/clipboard-win-5.4.1/supplement/DoumanAsh-clipboard-win-3b27cf2bfd1a-LICENSE": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/cosmic-text-0.15.0/fonts/FiraMono-LICENSE": "587dd9548304fd421cd254f7550bd101c1250ffc95417f2f7f92d55b44ecbe53",
"licenses/dependencies/cosmic-text-0.15.0/fonts/Inter-LICENSE": "3c8d13d97ea5eb62868833a377034c6be6a9833e768d32abec2a767a8101e4bc",
"licenses/dependencies/cosmic-text-0.15.0/fonts/NotoSans-LICENSE": "5ec4347054089def6904da61d04f0360968f9ef36634b1fe007a5b6ec2f7aa96",
"licenses/dependencies/fontdb-0.23.0/tests/fonts/LICENSE.txt": "b84fdd2c3da5db56385cdbb639795e90aa3e035c53bc3591135f18df3331451f",
"licenses/dependencies/gl_generator-0.14.0/supplement/brendanzab-gl-rs-ea503e8d5fb6-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/gpu-alloc-0.6.2/supplement/zakarumych-gpu-alloc-61020bdcb4eb-COPYING": "12121dfa588677007848ab922a45a1e3248868f6ff063598fceb3141d7897314",
"licenses/dependencies/gpu-alloc-types-0.3.1/supplement/zakarumych-gpu-alloc-7ddd1fe576fc-COPYING": "12121dfa588677007848ab922a45a1e3248868f6ff063598fceb3141d7897314",
"licenses/dependencies/gpu-descriptor-0.3.2/supplement/zakarumych-gpu-descriptor-bb28b4e55b74-COPYING": "f72143f7e9d9fb8bd336b139fa22f825a299591c29f2f7338c5566347b137613",
"licenses/dependencies/gpu-descriptor-types-0.2.0/supplement/zakarumych-gpu-descriptor-9f2fb9546591-COPYING": "f72143f7e9d9fb8bd336b139fa22f825a299591c29f2f7338c5566347b137613",
"licenses/dependencies/harfrust-0.3.2/scripts/ms-use/COPYING": "9906940f61b1f0b533fa7d99baf55178b2808fbe113ea51dfbfad8572ccd5f2b",
"licenses/dependencies/hexf-parse-0.2.1/supplement/CC0-1.0.txt": "a2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499",
"licenses/dependencies/hexf-parse-0.2.1/supplement/hexf-parse-0.2.1-Cargo.toml": "4a56dbdbc12054fd33b7a2634a45cbbe6fe12f5e6f4081002cbfa527f7220c70",
"licenses/dependencies/iced_core-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_core-0.14.0/src/layout/DRUID_LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/iced_debug-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_futures-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_graphics-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_graphics-0.14.0/assets/FiraSans-Regular.ttf/Fira-OFL.txt": "99bfb7c1e845b79d1031fcf37e678178eb4a8c7cc74a3f218ddf7223083a6fcd",
"licenses/dependencies/iced_graphics-0.14.0/assets/FiraSans-Regular.ttf/FiraSans-Regular-NOTICE.txt": "1e0baaa389b1647d06322ac9ea37822f31995408200ae5a2805a6b9bea0810d1",
"licenses/dependencies/iced_graphics-0.14.0/assets/Iced-Icons.ttf/Iced-Icons-NOTICE.txt": "8175634e30f84ef72a24c4965fb0e87f45a3c1274cc0e79e0473af582cffd1c4",
"licenses/dependencies/iced_graphics-0.14.0/assets/Iced-Icons.ttf/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_program-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_renderer-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_runtime-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_tiny_skia-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_wgpu-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_widget-0.14.2/supplement/iced-rs-iced-54abf81d13fe-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_winit-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/khronos_api-3.1.0/supplement/brendanzab-gl-rs-f150967b1c44-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/lyon-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_algorithms-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_algorithms-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_geom-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_geom-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_path-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_path-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_tessellation-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_tessellation-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/profiling-1.0.18/supplement/aclysma-profiling-8271551172eb-LICENSE-APACHE": "10d30a673cd5e9349bdc02aeb48f14b3386d27d0da32df8f0a555d4aa16aa551",
"licenses/dependencies/profiling-1.0.18/supplement/aclysma-profiling-8271551172eb-LICENSE-MIT": "c8167fdeeed46d3f244d3f85c5bf998ce889343691c32be2c61a8bc4b5c08333",
"licenses/dependencies/ring-0.17.14/src/polyfill/once_cell/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/ring-0.17.14/src/polyfill/once_cell/LICENSE-MIT": "6ee2ed6c77710de911761acd5fc1ad1da00f476beb1a7ef27e78c2d1858deafc",
"licenses/dependencies/ring-0.17.14/third_party/fiat/LICENSE": "9eacbcb81be660840c714a560a9d65ba07913db98dd4baf969f78dd499fdd60f",
"licenses/dependencies/spirv-0.3.0+sdk-1.3.268.0/supplement/gfx-rs-rspirv-e91a5debc10c-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/svg_fmt-0.4.5/supplement/nical-rust_debug-93f414cd572b-LICENSE": "7e98bed7f100747aaae7d82ab94fbe6b76fd6b84b09a3aaa413bff8196d0fbb1",
"licenses/dependencies/tracing-core-0.1.36/src/spin/LICENSE": "58545fed1565e42d687aecec6897d35c6d37ccb71479a137c0deb2203e125c79",
"licenses/dependencies/ttf-parser-0.25.1/tests/fonts/colr_1_LICENSE": "58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd"
},
"fileCount": 559,
"originalHelper": {
"path": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911.py",
"sha256": "951b1f4b913972c5c90b17e3e70f3644c4c9328d82372a325ee46debb345237a",
"unchanged": true
},
"newHelper": {
"path": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-v2-20260911.py",
"sha256": "9637ac8f5b9cd97ce672e0bd6b891454b2145a6236421d82536b8bdb2d66bc3c",
"syntaxParse": "PASS"
},
"sourceDiff": "--- contextual-prerelease-gui-20260911.py\n+++ contextual-prerelease-gui-v2-20260911.py\n@@ -9,7 +9,7 @@\n import subprocess\n \n root = Path(__file__).resolve().parents[1]\n-trial = root / '.local/contextual-prerelease-gui-20260911'\n+trial = root / '.local/contextual-prerelease-gui-20260911-v2'\n base = root / 'harness/fixtures/staged-source-authoring/base'\n oracle = root / '.local/staged-source-oracle-20260911/staged-source-authoring-contract.exe'\n expected = {\n@@ -33,8 +33,13 @@\n def now():\n return datetime.datetime.now(datetime.timezone.utc).isoformat()\n def minimal_environment(package):\n- system = next(v for k, v in os.environ.items() if k.upper() == 'SYSTEMROOT')\n- return {'SystemRoot': system, 'WINDIR': system,\n+ parent = {key.upper(): value for key, value in os.environ.items()}\n+ names = ('SystemRoot', 'SystemDrive', 'ProgramData', 'ALLUSERSPROFILE', 'PUBLIC')\n+ assert all(parent.get(name.upper()) for name in names), 'Required standard Windows path is missing'\n+ standard = {name: parent[name.upper()] for name in names}\n+ assert all('%' not in value for value in standard.values()), 'Unexpanded standard Windows path'\n+ system = standard['SystemRoot']\n+ return {**standard, 'WINDIR': system,\n 'PATH': system + '\\\\System32;' + system,\n 'USERPROFILE': str(trial / 'profile'),\n 'LOCALAPPDATA': str(trial / 'profile/local'),\n@@ -59,7 +64,7 @@\n assert args.package and args.package.is_dir()\n package = args.package.resolve()\n assert package.name == 'ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm'\n- assert 'contextual-prerelease-review-20260911' in package.parts\n+ assert package == (root / '.local/contextual-prerelease-extraction2-20260911' / package.name).resolve()\n review_path = root / '.local/contextual-prerelease-review-20260911/artifact-result.json'\n review = json.loads(review_path.read_bytes())\n assert review['status'] == 'PASS'\n@@ -67,7 +72,7 @@\n assert before == review['archive']['files']\n assert all(before[p] == h for p, h in expected.items())\n trial.mkdir(exist_ok=False)\n- for folder in ('profile/local', 'profile/roaming', 'tmp'):\n+ for folder in ('profile/local', 'profile/roaming', 'profile/Desktop', 'tmp'):\n (trial / folder).mkdir(parents=True)\n assert inventory(base) == {\n 'project.arcadia': 'aa844950ec4fb86f262a257e1fc370a26557ea7978d8a4cab78265037660234c',\n",
"unchangedFunctionSyntax": [
"sha",
"inventory",
"record",
"now",
"run_oracle"
],
"standardParentPaths": {
"SystemRoot": "C:\\Windows",
"SystemDrive": "C:",
"ProgramData": "C:\\ProgramData",
"ALLUSERSPROFILE": "C:\\ProgramData",
"PUBLIC": "C:\\Users\\Public"
},
"trial": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2",
"trialExists": false,
"rationale": [
"First trial preserved all 559 original package files but Windows created a literal %SystemDrive% cache path because the minimal environment omitted SystemDrive.",
"Forward only the named nonsecret Windows standard paths; keep Windows-only PATH and private USERPROFILE, APPDATA, LOCALAPPDATA, TEMP/TMP.",
"Create private profile/Desktop before GUI launch so native Open has a valid Desktop.",
"Fresh exact extraction isolates the earlier cache side effect without deleting or changing old evidence; complete package/oracle/hash guards remain intact."
],
"readyCommand": [
"C:/Users/User/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-v2-20260911.py",
"launch",
"--package",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-extraction2-20260911\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm"
]
}
@@ -0,0 +1,104 @@
"""Launch/check the independently extracted package; native input is separate."""
import argparse
import datetime
import hashlib
import json
import os
from pathlib import Path
import shutil
import subprocess
root = Path(__file__).resolve().parents[1]
trial = root / '.local/contextual-prerelease-gui-20260911'
base = root / 'harness/fixtures/staged-source-authoring/base'
oracle = root / '.local/staged-source-oracle-20260911/staged-source-authoring-contract.exe'
expected = {
'arcadia-studio.exe': '5657bab5c841939b66f901efe6c0ffb2d7cbbe8cc5f111a0ca3de8073d3846ce',
'arcadia-server.exe': 'efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665',
'libunwind.dll': 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4',
}
def sha(p):
return hashlib.sha256(p.read_bytes()).hexdigest()
def inventory(folder):
found = {}
for p in folder.rglob('*'):
assert not p.is_symlink() and not (getattr(p.lstat(), 'st_file_attributes', 0) & 0x400), str(p)
if p.is_file():
found[p.relative_to(folder).as_posix()] = sha(p)
return found
def record(path, value):
with path.open('x', encoding='utf-8', newline='\n') as f:
json.dump(value, f, indent=2)
f.write('\n')
def now():
return datetime.datetime.now(datetime.timezone.utc).isoformat()
def minimal_environment(package):
system = next(v for k, v in os.environ.items() if k.upper() == 'SYSTEMROOT')
return {'SystemRoot': system, 'WINDIR': system,
'PATH': system + '\\System32;' + system,
'USERPROFILE': str(trial / 'profile'),
'LOCALAPPDATA': str(trial / 'profile/local'),
'APPDATA': str(trial / 'profile/roaming'),
'TEMP': str(trial / 'tmp'), 'TMP': str(trial / 'tmp')}
def run_oracle(package, args, label):
assert sha(oracle) == '967d9ba3c6fb3a7efb410833903ec94556ca2d48a67d5072c8bb160f40a00f9c'
env = minimal_environment(package)
env['PATH'] = str(package) + ';' + env['PATH']
result = subprocess.run([str(oracle), *args], env=env, capture_output=True)
(trial / (label + '.stdout.log')).write_bytes(result.stdout)
(trial / (label + '.stderr.log')).write_bytes(result.stderr)
record(trial / (label + '.json'), {'atUtc': now(), 'args': args, 'exitCode': result.returncode,
'oracleSha256': sha(oracle)})
assert result.returncode == 0, result.stdout.decode(errors='replace') + result.stderr.decode(errors='replace')
parser = argparse.ArgumentParser()
parser.add_argument('action', choices=['launch', 'saved', 'closed'])
parser.add_argument('--package', type=Path)
args = parser.parse_args()
if args.action == 'launch':
assert args.package and args.package.is_dir()
package = args.package.resolve()
assert package.name == 'ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm'
assert 'contextual-prerelease-review-20260911' in package.parts
review_path = root / '.local/contextual-prerelease-review-20260911/artifact-result.json'
review = json.loads(review_path.read_bytes())
assert review['status'] == 'PASS'
before = inventory(package)
assert before == review['archive']['files']
assert all(before[p] == h for p, h in expected.items())
trial.mkdir(exist_ok=False)
for folder in ('profile/local', 'profile/roaming', 'tmp'):
(trial / folder).mkdir(parents=True)
assert inventory(base) == {
'project.arcadia': 'aa844950ec4fb86f262a257e1fc370a26557ea7978d8a4cab78265037660234c',
'notes.arcadia': 'ad9de02963c20d1f43856455a797deb05ca674659e45f2c4b96b52783024f8bd'}
shutil.copytree(base, trial / 'work')
run_oracle(package, ['same', str(base / 'project.arcadia'), str(trial / 'work/project.arcadia')], 'baseline')
env = minimal_environment(package)
startup = subprocess.STARTUPINFO()
startup.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startup.wShowWindow = 0
with (trial / 'stdout.log').open('xb') as out, (trial / 'stderr.log').open('xb') as err:
process = subprocess.Popen([str(package / 'arcadia-studio.exe')], cwd=package,
env=env, stdout=out, stderr=err, startupinfo=startup)
record(trial / 'package-before.json', before)
launch = {'atUtc': now(), 'pid': process.pid, 'package': str(package), 'environment': env,
'reviewSha256': sha(review_path), 'archiveSha256': review['archive']['sha256'],
'source': str(trial / 'work/project.arcadia'), 'scope': 'Fresh extracted package; native acceptance pending'}
record(trial / 'launch.json', launch)
print(json.dumps(launch, indent=2))
else:
launch = json.loads((trial / 'launch.json').read_bytes())
package = Path(launch['package'])
assert inventory(package) == json.loads((trial / 'package-before.json').read_bytes())
if args.action == 'saved':
destination = trial / 'checkpoint-first'
assert not destination.exists()
shutil.copytree(trial / 'work', destination)
run_oracle(package, ['check', 'lifeline', str(base / 'project.arcadia'),
str(destination / 'project.arcadia'), str(destination / 'project.arcadia')], 'saved')
record(trial / 'saved-files.json', inventory(destination))
else:
record(trial / 'package-after-close.json', {'atUtc': now(), 'files': len(inventory(package)),
'completeInventoryUnchanged': True})
print(json.dumps({'action': args.action, 'result': 'PASS', 'packageFiles': len(inventory(package))}))
@@ -0,0 +1,109 @@
"""Launch/check the independently extracted package; native input is separate."""
import argparse
import datetime
import hashlib
import json
import os
from pathlib import Path
import shutil
import subprocess
root = Path(__file__).resolve().parents[1]
trial = root / '.local/contextual-prerelease-gui-20260911-v2'
base = root / 'harness/fixtures/staged-source-authoring/base'
oracle = root / '.local/staged-source-oracle-20260911/staged-source-authoring-contract.exe'
expected = {
'arcadia-studio.exe': '5657bab5c841939b66f901efe6c0ffb2d7cbbe8cc5f111a0ca3de8073d3846ce',
'arcadia-server.exe': 'efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665',
'libunwind.dll': 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4',
}
def sha(p):
return hashlib.sha256(p.read_bytes()).hexdigest()
def inventory(folder):
found = {}
for p in folder.rglob('*'):
assert not p.is_symlink() and not (getattr(p.lstat(), 'st_file_attributes', 0) & 0x400), str(p)
if p.is_file():
found[p.relative_to(folder).as_posix()] = sha(p)
return found
def record(path, value):
with path.open('x', encoding='utf-8', newline='\n') as f:
json.dump(value, f, indent=2)
f.write('\n')
def now():
return datetime.datetime.now(datetime.timezone.utc).isoformat()
def minimal_environment(package):
parent = {key.upper(): value for key, value in os.environ.items()}
names = ('SystemRoot', 'SystemDrive', 'ProgramData', 'ALLUSERSPROFILE', 'PUBLIC')
assert all(parent.get(name.upper()) for name in names), 'Required standard Windows path is missing'
standard = {name: parent[name.upper()] for name in names}
assert all('%' not in value for value in standard.values()), 'Unexpanded standard Windows path'
system = standard['SystemRoot']
return {**standard, 'WINDIR': system,
'PATH': system + '\\System32;' + system,
'USERPROFILE': str(trial / 'profile'),
'LOCALAPPDATA': str(trial / 'profile/local'),
'APPDATA': str(trial / 'profile/roaming'),
'TEMP': str(trial / 'tmp'), 'TMP': str(trial / 'tmp')}
def run_oracle(package, args, label):
assert sha(oracle) == '967d9ba3c6fb3a7efb410833903ec94556ca2d48a67d5072c8bb160f40a00f9c'
env = minimal_environment(package)
env['PATH'] = str(package) + ';' + env['PATH']
result = subprocess.run([str(oracle), *args], env=env, capture_output=True)
(trial / (label + '.stdout.log')).write_bytes(result.stdout)
(trial / (label + '.stderr.log')).write_bytes(result.stderr)
record(trial / (label + '.json'), {'atUtc': now(), 'args': args, 'exitCode': result.returncode,
'oracleSha256': sha(oracle)})
assert result.returncode == 0, result.stdout.decode(errors='replace') + result.stderr.decode(errors='replace')
parser = argparse.ArgumentParser()
parser.add_argument('action', choices=['launch', 'saved', 'closed'])
parser.add_argument('--package', type=Path)
args = parser.parse_args()
if args.action == 'launch':
assert args.package and args.package.is_dir()
package = args.package.resolve()
assert package.name == 'ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm'
assert package == (root / '.local/contextual-prerelease-extraction2-20260911' / package.name).resolve()
review_path = root / '.local/contextual-prerelease-review-20260911/artifact-result.json'
review = json.loads(review_path.read_bytes())
assert review['status'] == 'PASS'
before = inventory(package)
assert before == review['archive']['files']
assert all(before[p] == h for p, h in expected.items())
trial.mkdir(exist_ok=False)
for folder in ('profile/local', 'profile/roaming', 'profile/Desktop', 'tmp'):
(trial / folder).mkdir(parents=True)
assert inventory(base) == {
'project.arcadia': 'aa844950ec4fb86f262a257e1fc370a26557ea7978d8a4cab78265037660234c',
'notes.arcadia': 'ad9de02963c20d1f43856455a797deb05ca674659e45f2c4b96b52783024f8bd'}
shutil.copytree(base, trial / 'work')
run_oracle(package, ['same', str(base / 'project.arcadia'), str(trial / 'work/project.arcadia')], 'baseline')
env = minimal_environment(package)
startup = subprocess.STARTUPINFO()
startup.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startup.wShowWindow = 0
with (trial / 'stdout.log').open('xb') as out, (trial / 'stderr.log').open('xb') as err:
process = subprocess.Popen([str(package / 'arcadia-studio.exe')], cwd=package,
env=env, stdout=out, stderr=err, startupinfo=startup)
record(trial / 'package-before.json', before)
launch = {'atUtc': now(), 'pid': process.pid, 'package': str(package), 'environment': env,
'reviewSha256': sha(review_path), 'archiveSha256': review['archive']['sha256'],
'source': str(trial / 'work/project.arcadia'), 'scope': 'Fresh extracted package; native acceptance pending'}
record(trial / 'launch.json', launch)
print(json.dumps(launch, indent=2))
else:
launch = json.loads((trial / 'launch.json').read_bytes())
package = Path(launch['package'])
assert inventory(package) == json.loads((trial / 'package-before.json').read_bytes())
if args.action == 'saved':
destination = trial / 'checkpoint-first'
assert not destination.exists()
shutil.copytree(trial / 'work', destination)
run_oracle(package, ['check', 'lifeline', str(base / 'project.arcadia'),
str(destination / 'project.arcadia'), str(destination / 'project.arcadia')], 'saved')
record(trial / 'saved-files.json', inventory(destination))
else:
record(trial / 'package-after-close.json', {'atUtc': now(), 'files': len(inventory(package)),
'completeInventoryUnchanged': True})
print(json.dumps({'action': args.action, 'result': 'PASS', 'packageFiles': len(inventory(package))}))
@@ -0,0 +1,10 @@
{
"atUtc": "2026-09-11T16:22:25.531203+00:00",
"args": [
"same",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\harness\\fixtures\\staged-source-authoring\\base\\project.arcadia",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\work\\project.arcadia"
],
"exitCode": 0,
"oracleSha256": "967d9ba3c6fb3a7efb410833903ec94556ca2d48a67d5072c8bb160f40a00f9c"
}
@@ -0,0 +1 @@
PASS exact model/identity/2 reachable sources; 2 exact disk files (0 proven retained)
@@ -0,0 +1 @@
// Preserve this independent engineering note: secours 雨 Δ.
@@ -0,0 +1,7 @@
oa_activity assess_incident_work "Assess incident work" id "3e617adf-fdbb-4dc4-9cbc-73309a382c5d" {
description "";
parent none;
}
@@ -0,0 +1,25 @@
arcadia 7;
project contextual_source_acceptance "Contextual source acceptance" id "d1510000-0000-4000-8000-000000000001" {
include "notes.arcadia";
// The viewpoint is explicit before any lifeline exists.
oa_scenario operational_assessment "Operational assessment" id "d1510000-0000-4000-8000-000000000002" {
viewpoint OperationalActivity;
steps [];
oa_lifeline assessment_lifeline "Assessment lifeline" id "8d1cdc7a-c7c2-4d97-9b54-c590ff515717" {
description "";
represented @assess_incident_work;
}
}
// Contributions are occurrences; root Functions are separate sources.
sa_functional_chain system_assessment "System assessment" id "d1510000-0000-4000-8000-000000000003" {
steps [];
}
include "oa/activities/activity_assess_incident_work.arcadia";
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

@@ -0,0 +1,19 @@
{
"atUtc": "2026-09-11T16:22:25.882919+00:00",
"pid": 9764,
"package": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-review-20260911\\extracted\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm",
"environment": {
"SystemRoot": "C:\\Windows",
"WINDIR": "C:\\Windows",
"PATH": "C:\\Windows\\System32;C:\\Windows",
"USERPROFILE": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\profile",
"LOCALAPPDATA": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\profile\\local",
"APPDATA": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\profile\\roaming",
"TEMP": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\tmp",
"TMP": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\tmp"
},
"reviewSha256": "3a6bf2580b25dad696d635dcbbde88522a065f83698229c2a22dda92f2ab6ee8",
"archiveSha256": "9186d4fc9a7b52fb195c183c4847c8e3419ea6da8b3f907e0c06f9ceec58dee0",
"source": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\work\\project.arcadia",
"scope": "Fresh extracted package; native acceptance pending"
}
@@ -0,0 +1,130 @@
[
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-review-20260911\\extracted\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm\\arcadia-studio.exe",
"C:\\Windows\\SYSTEM32\\ntdll.dll",
"C:\\Windows\\System32\\KERNEL32.DLL",
"C:\\Windows\\System32\\KERNELBASE.dll",
"C:\\Windows\\SYSTEM32\\apphelp.dll",
"C:\\Windows\\System32\\user32.dll",
"C:\\Windows\\System32\\win32u.dll",
"C:\\Windows\\System32\\GDI32.dll",
"C:\\Windows\\System32\\gdi32full.dll",
"C:\\Windows\\System32\\msvcp_win.dll",
"C:\\Windows\\System32\\ucrtbase.dll",
"C:\\Windows\\System32\\ole32.dll",
"C:\\Windows\\System32\\combase.dll",
"C:\\Windows\\System32\\RPCRT4.dll",
"C:\\Windows\\System32\\advapi32.dll",
"C:\\Windows\\System32\\msvcrt.dll",
"C:\\Windows\\System32\\sechost.dll",
"C:\\Windows\\System32\\bcryptprimitives.dll",
"C:\\Windows\\System32\\shell32.dll",
"C:\\Windows\\System32\\imm32.dll",
"C:\\Windows\\System32\\ws2_32.dll",
"C:\\Windows\\System32\\oleaut32.dll",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-review-20260911\\extracted\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm\\libunwind.dll",
"C:\\Windows\\SYSTEM32\\bcrypt.dll",
"C:\\Windows\\SYSTEM32\\dwmapi.dll",
"C:\\Windows\\SYSTEM32\\uxtheme.dll",
"C:\\Windows\\SYSTEM32\\opengl32.dll",
"C:\\Windows\\SYSTEM32\\GLU32.dll",
"C:\\Windows\\SYSTEM32\\CRYPTBASE.DLL",
"C:\\Windows\\SYSTEM32\\dxcore.dll",
"C:\\Windows\\System32\\MSCTF.dll",
"C:\\Windows\\SYSTEM32\\uiautomationcore.dll",
"C:\\Windows\\SYSTEM32\\kernel.appcore.dll",
"C:\\Windows\\System32\\clbcatq.dll",
"C:\\Windows\\system32\\dataexchange.dll",
"C:\\Windows\\system32\\twinapi.appcore.dll",
"C:\\Windows\\system32\\explorerframe.dll",
"C:\\Windows\\System32\\SHCORE.dll",
"C:\\Windows\\System32\\SHLWAPI.dll",
"C:\\Windows\\System32\\Windows.Storage.dll",
"C:\\Windows\\SYSTEM32\\powrprof.dll",
"C:\\Windows\\SYSTEM32\\UMPDC.dll",
"C:\\Windows\\SYSTEM32\\CFGMGR32.dll",
"C:\\Windows\\system32\\dxgi.dll",
"C:\\Windows\\SYSTEM32\\windows.staterepositorycore.dll",
"C:\\Windows\\SYSTEM32\\directxdatabasehelper.dll",
"C:\\Windows\\SYSTEM32\\d3d12.dll",
"C:\\Windows\\SYSTEM32\\d3dcompiler_47.dll",
"C:\\Windows\\SYSTEM32\\cryptsp.dll",
"C:\\Windows\\System32\\DriverStore\\FileRepository\\vm3d.inf_amd64_39d3dfd189710365\\vm3dgl64.dll",
"C:\\Windows\\System32\\DriverStore\\FileRepository\\vm3d.inf_amd64_39d3dfd189710365\\vm3dglhelper64.dll",
"C:\\Windows\\SYSTEM32\\WINMM.dll",
"C:\\Windows\\SYSTEM32\\D3D12Core.dll",
"C:\\Windows\\SYSTEM32\\d3d10warp.dll",
"C:\\Windows\\SYSTEM32\\D3DSCache.dll",
"C:\\Windows\\SYSTEM32\\USERENV.dll",
"C:\\Windows\\SYSTEM32\\dxilconv.dll",
"C:\\Windows\\SYSTEM32\\dcomp.dll",
"C:\\Windows\\SYSTEM32\\Microsoft.Internal.WarpPal.dll",
"C:\\Windows\\SYSTEM32\\textinputframework.dll",
"C:\\Windows\\SYSTEM32\\OLEACC.dll",
"C:\\Windows\\System32\\threadpoolwinrt.dll",
"C:\\Windows\\System32\\DUI70.dll",
"C:\\Windows\\WinSxS\\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8457_none_3e0b2faee331e92d\\Comctl32.dll",
"C:\\Windows\\System32\\DUser.dll",
"C:\\Windows\\SYSTEM32\\CoreMessaging.dll",
"C:\\Windows\\SYSTEM32\\CoreUIComponents.dll",
"C:\\Windows\\SYSTEM32\\wintypes.dll",
"C:\\Windows\\SYSTEM32\\TextShaping.dll",
"C:\\Windows\\SYSTEM32\\edputil.dll",
"C:\\Windows\\SYSTEM32\\WindowsCodecs.dll",
"C:\\Windows\\System32\\profapi.dll",
"C:\\Windows\\System32\\thumbcache.dll",
"C:\\Windows\\SYSTEM32\\policymanager.dll",
"C:\\Windows\\System32\\Windows.Globalization.dll",
"C:\\Windows\\SYSTEM32\\globinputhost.dll",
"C:\\Windows\\SYSTEM32\\Bcp47Langs.dll",
"C:\\Windows\\System32\\PROPSYS.dll",
"C:\\Windows\\System32\\urlmon.dll",
"C:\\Windows\\System32\\iertutil.dll",
"C:\\Windows\\System32\\srvcli.dll",
"C:\\Windows\\System32\\netutils.dll",
"C:\\Windows\\system32\\rsaenh.dll",
"C:\\Windows\\System32\\XmlLite.dll",
"C:\\Windows\\system32\\NetworkExplorer.dll",
"C:\\Windows\\SYSTEM32\\sxs.dll",
"C:\\Windows\\SYSTEM32\\atlthunk.dll",
"C:\\Windows\\System32\\StructuredQuery.dll",
"C:\\Windows\\System32\\icu.dll",
"C:\\Windows\\System32\\OneCoreUAPCommonProxyStub.dll",
"C:\\Windows\\System32\\Windows.FileExplorer.Common.dll",
"C:\\Windows\\System32\\OneCoreCommonProxyStub.dll",
"C:\\Windows\\System32\\Windows.System.Launcher.dll",
"C:\\Windows\\System32\\Windows.StateRepositoryPS.dll",
"C:\\Windows\\system32\\windowsudk.shellcommon.dll",
"C:\\Windows\\System32\\Windows.UI.dll",
"C:\\Windows\\system32\\Windows.Storage.Search.dll",
"C:\\Windows\\System32\\Windows.UI.Immersive.dll",
"C:\\Windows\\SYSTEM32\\ntshrui.dll",
"C:\\Windows\\SYSTEM32\\cscapi.dll",
"C:\\Windows\\System32\\ActXPrxy.dll",
"C:\\Windows\\System32\\EhStorShell.dll",
"C:\\Windows\\System32\\SETUPAPI.dll",
"C:\\Windows\\System32\\cscui.dll",
"C:\\Windows\\System32\\SspiCli.dll",
"C:\\Windows\\System32\\MPR.dll",
"C:\\Windows\\System32\\vmhgfs.dll",
"C:\\Windows\\System32\\VERSION.dll",
"C:\\Windows\\System32\\VCRUNTIME140.dll",
"C:\\Windows\\System32\\p9np.dll",
"C:\\Windows\\System32\\drprov.dll",
"C:\\Windows\\System32\\ntlanman.dll",
"C:\\Windows\\System32\\davclnt.dll",
"C:\\Windows\\System32\\WINSTA.dll",
"C:\\Windows\\System32\\wkscli.dll",
"C:\\Windows\\System32\\dlnashext.dll",
"C:\\Windows\\System32\\PlayToDevice.dll",
"C:\\Windows\\System32\\DevDispItemProvider.dll",
"C:\\Windows\\System32\\MMDevApi.dll",
"C:\\Windows\\System32\\DEVOBJ.dll",
"C:\\Windows\\system32\\wpdshext.dll",
"C:\\Windows\\WinSxS\\amd64_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.26100.8328_none_6ef30b123dc73046\\gdiplus.dll",
"C:\\Windows\\System32\\PortableDeviceApi.dll",
"C:\\Windows\\System32\\WINTRUST.dll",
"C:\\Windows\\System32\\CRYPT32.dll",
"C:\\Windows\\SYSTEM32\\MSASN1.dll",
"C:\\Windows\\System32\\EhStorAPI.dll",
"C:\\Windows\\System32\\WTSAPI32.dll"
]
@@ -0,0 +1,19 @@
{
"atUtc": "2026-09-11T16:32:47.558612+00:00",
"scope": "Complete model/source check only; this initial native trial failed package inventory because of an added Windows shell cache",
"exitCode": 0,
"args": [
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\staged-source-oracle-20260911\\staged-source-authoring-contract.exe",
"check",
"lifeline",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\harness\\fixtures\\staged-source-authoring\\base\\project.arcadia",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\checkpoint-first\\project.arcadia",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911\\checkpoint-first\\project.arcadia"
],
"oracleSha256": "967d9ba3c6fb3a7efb410833903ec94556ca2d48a67d5072c8bb160f40a00f9c",
"files": {
"notes.arcadia": "ad9de02963c20d1f43856455a797deb05ca674659e45f2c4b96b52783024f8bd",
"project.arcadia": "82297ccc2eae444f9ec7caca793ce71b2340904014289e36f8a6bc587f640f23",
"oa/activities/activity_assess_incident_work.arcadia": "6fe331b65e7e9489221dd8914d26fa188d4941c1641685f5c24a4320cdb9c857"
}
}
@@ -0,0 +1 @@
PASS Lifeline: complete Project + 3 exact source/disk files, original role UUIDs
Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

@@ -0,0 +1,8 @@
{
"atUtc": "2026-09-11T16:33:13.2669723+00:00",
"pid": 9764,
"absent": true,
"method": "Native Alt+F4 after complete saved-model check",
"exitCode": null,
"packageAcceptance": "Failed initial environment fixture: extra shell cache; original559 files unchanged"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

@@ -0,0 +1,561 @@
{
"arcadia-server.exe": "efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665",
"arcadia-studio.exe": "5657bab5c841939b66f901efe6c0ffb2d7cbbe8cc5f111a0ca3de8073d3846ce",
"dependency-notices.json": "f318f87e6a23dcfac16ef7b1cfe51ecb804e98e1ff6a97271180319d5922fc0e",
"documentation-check.json": "bcc89585951fd9e5a1641993c51ca79e00a7a06944a8273d2df413331320e93f",
"libunwind.dll": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"package.json": "25f01823dbceed15468bf759eed3f9ffbfd1098427027288bcbb9a3d356b6a4d",
"README.md": "597cfb8da873e019d2658420f18ec059f0185fa9106ff9eafe934dfdd6ed266b",
"SHA256SUMS.txt": "04e4be3f6a081e11ccad8609643031d91fed82cd08e7c7821002ff9b9a04e454",
"START-HERE.txt": "a549295cf57ac73673dc4fa6106463450f982122793cb9c7135ce4fc7087e9ed",
"THIRD-PARTY-NOTICES.txt": "6756989c8fc73706641cd78449c315458425a2eed9a82febc289b9d28ea7f21f",
"deployment/arcadia-server.service": "1e6c6bb4065e25f8fe1d558a4ed0bbd4844782a4377c2482488db1e6f9cab01d",
"deployment/Dockerfile": "72c04aef4ec879955ed3bdf315987553d018ef46e4b8f350f0f6fe380c453eb7",
"deployment/Dockerfile.dockerignore": "6bb7d7496110b11a531cb8cd923864c6610850a8f1c4de8a797f54c7156f29e1",
"docs/api.html": "a06126cb741da57e9c06e83fc4137ccde0de05562673546bc9d405878f51ea07",
"docs/api.rst": "ca7d310138c3b4d429d80a1d03d1ac8d4a9296069e205da573034256d10438a7",
"docs/language.html": "67dcfa3477b48a0b07298ec81741840cc3ccff12c7d58164873d746d41d611c8",
"docs/language.rst": "ac6b1d982c55f246de2f3c844b24b874599a3c20cfbd7ed22efe4561ac622b83",
"docs/linux-packaging.md": "41a1bb1095801df37a1411341c5791d55ea8c365739314d599a60269ac4bc7a0",
"docs/openapi.json": "c6ae512f791a939eaf6ec5e5e78e9468bdee0e028092d00098bd90ad9498d967",
"docs/research-v2-service.md": "4828df5bc679e7c71f49b4b85c9e7dacbec52f46d416fed48af70e08886d4e4e",
"docs/server.md": "4eb24937d424ba8b384e1734e02a6f8e963ae11d2715889c92b14b39ff2e4a48",
"docs/windows-packaging.md": "2c852ff7041713ffbff3c951ac98df647c51fb70b0feba9000f7bfd5bc2703a8",
"examples/coastal-rescue.arcadia": "7e183ef9fd8154d3074303f1956cd0d9871c19e3ffc630d333b0bffbd6e30e17",
"examples/coastal-rescue.json": "242f0b031229a87af5c4ebe5d651defe59c191a6b7a69dc0a77f7e203411f195",
"examples/legacy-v1-coastal-rescue.arcadia": "4dbbbdf8bc7e6cb8e0a81dd678069dae585a9e5187c59bc3665e1fdab3f1a86a",
"examples/legacy-v1-coastal-rescue.oa.json": "fd0e9dedfb7adb922dc0575cc2b820d40344d639f1d8052bd70363aa59de9c24",
"examples/routing-workshop.arcadia": "dc6b75da72884d399132ed9e300fa5a26b73d802bb526c9af986ae9eeb0a646a",
"examples/routing-workshop.json": "8592714f75b271133f21ce017d87896b6cf91ea0e4837f1c2ed453e21be26b14",
"licenses/llvm-mingw-LICENSE.TXT": "8d85c1057d742e597985c7d4e6320b015a9139385cff4cbae06ffc0ebe89afee",
"examples/release1/expected-diagnostics.json": "3700393d76b940cfc076bf52861bd7b1f43370f8eabce3594531bd0bf1fc851e",
"examples/release1/model.json": "ef0ef4006c3e09d5db6e1b621256b3f7d6642f3a7b09cc34607cfbcca830c727",
"examples/release1/model.rs": "15f30f6bde655808fe754665c26d560e36f2a9bad340f346b09137d0d05045f5",
"examples/release1/project.arcadia": "b2674e6bf77cfe0f6f0ba79c81d2e96d92f39c02ca2c6266d80e91723bfb9fda",
"examples/release1/README.md": "113cfb1cf38a98b51bff60442d86a35d636a3d80ef206bece7d53d0aae67f2d5",
"examples/release1/traceability.arcadia": "48a96f543456c9b5a5798fc795594e4119147fe45f11a6f109f141b7f514560f",
"examples/release1/transition-before.json": "2253e6434f741687e22327c37d520ed15c043bc36025498650bc2366bb6a874d",
"examples/release1/transition-request.json": "43b9a22e5f95ad3bc0ebd2478ead0e14406854abc989ae94ded9367b013d812a",
"examples/source-project/oa.arcadia": "5f60642f211b2d352a951092faeeb7503d4fb7f6f7fca99e810347231101d31c",
"examples/source-project/project.arcadia": "787f6b67b179ffd221f7e5faf1a4edd74cfd116aa1e3b5e9ed9f22fbff612d8d",
"examples/source-project/views.arcadia": "e29ad3f406a6a50d2f0ae2ca2a53ee3b0c18222cd4098704a46d4f48b64ea17f",
"examples/text-first/project.arcadia": "f441535c623e0cf20e1875eb2cd33b587ed00e078c37af39cb36d89bb5edc19a",
"examples/text-first/README.md": "4ec8250d5ed556f1d496e8c85137e973e802ecb11df1a36488411e8cdc5a9f9e",
"examples/release1/evidence/repair-check.md": "f4db17bdca4ecbb1bf0caef01b2da5f1f7f798ab3152b648ce6dd8696a6a68e5",
"examples/release1/oa/capabilities.arcadia": "fc8012e5554350b12e1cb80080f8feab80d933c9b33c0f2a7bb500cb7d609936",
"examples/release1/oa/model.arcadia": "f7cf914766ea73ec53b85e32d117ea9a9dba52d3e038246863541ae7069b1a15",
"examples/release1/oa/participants.arcadia": "951764c14179f27c10e315acf2ea37d1fff54c77b8441e23addd239e8c715ce3",
"examples/release1/oa/types.arcadia": "9d0396fb82dd5733edd8d1cf52f968ca84906927c704f9cf0944a7fae215cf49",
"examples/release1/sa/capabilities.arcadia": "b6912fb3ece439912345fa71724acd462e716a1e5a88203a1058a5c3b2c20a4f",
"examples/release1/sa/model.arcadia": "d431509251acb859fbb98733b6d18add952495e10a78703fbe8f31e40bc083c4",
"examples/release1/sa/participants.arcadia": "780d2eb08b217b67b55febb3d34846f727b8ee9018df6c5741748647e36b2ff8",
"examples/release1/sa/types.arcadia": "101fc0fbd99f1101514aa7b6da4f8e535aae0bb94c9e2b9e7e6c151135b28660",
"examples/release1/views/diagram_oa_allocation_view.arcadia": "dfc0eb61e0e2aa5bda45524571fbfa3494f44ce19696f3e15e07438074a07bc7",
"examples/release1/views/diagram_sa_allocation_view.arcadia": "b78b43a26a82efb8fbd5374b09c329fa341f57b29f635d397b9ef8aede71d389",
"examples/release1/views/diagram_sa_capability_view.arcadia": "75e8dc9fb30f25d6f8fd3c6b595593ab4f98958a25798f961e336e0fac557649",
"examples/release1/views/diagram_sa_service_view.arcadia": "b08c84f3ea633e7c78dfdad3272f75415f6256cf3614b6d99bfd4f0269076c9b",
"examples/release1/views/diagram_sa_state_view.arcadia": "5f42f4c605e57b817d8400ed21f2b14bfc4e1592aebe941ff113767504c2b869",
"examples/release1/oa/activities/activity_oa_restore_work.arcadia": "83e73d0a013d5c3e1a4af0d9139ab0cfa362d25a846671fc2dac59181061a9d4",
"examples/release1/oa/behavior/process_oa_assessment_procedure.arcadia": "172c32c044ef4b5bc58a1f4635cc81f48dabb4014479b47dce7b25fedf2dbd0d",
"examples/release1/oa/behavior/process_oa_field_procedure.arcadia": "d2552dc5383e2e91cb302a790364e197f663c2edc013a2ab1978789825c9c324",
"examples/release1/oa/behavior/process_oa_response.arcadia": "cf86f46fa5c5d70592ef43f1bc1cb4d968efd8add384ba88036bef6b88aa4abc",
"examples/release1/oa/behavior/scenario_oa_conversation.arcadia": "b25be524e98a35ebac5e4481b7609c027b32baf9605e8097f807560f94a77ca6",
"examples/release1/oa/behavior/scenario_oa_full_scenario.arcadia": "00a1edf2c9707a0eb62ac070c2d02467874f2c9c1f273cc6ddb53d6d65999a1c",
"examples/release1/oa/behavior/state_machine_oa_monitor.arcadia": "447c9ad1359f4a31ecf975ad07c0b08d8e7e03191fb0858e2fc56f377b223cd5",
"examples/release1/sa/behavior/process_sa_assessment_procedure.arcadia": "73928ced61c06cbc08728d7956676a50fd4c05aa5b7f1ff4f29ce27a0b0f2088",
"examples/release1/sa/behavior/process_sa_field_procedure.arcadia": "886d462af83110cbfa55dd232a667ea1446761234471357cbb878794e98e8768",
"examples/release1/sa/behavior/process_sa_response.arcadia": "041785fc22842423822431bd5e6e8d16094ebd0716965e7c765fb8c1d7549e8a",
"examples/release1/sa/behavior/scenario_sa_conversation.arcadia": "97276f5757ee9aa12a0dbd9d3ccd58174b3091162bb8bcce357cec20a45f5d85",
"examples/release1/sa/behavior/scenario_sa_full_scenario.arcadia": "e12fc406b99d60a2f7768aaa0b25ba560e8605f0b8e37f3a7cdd3b8443562b74",
"examples/release1/sa/behavior/state_machine_sa_monitor.arcadia": "05ce29af99424c491c47fe2450dc6f5f8ce995511c01ec7e17bb5855be3c9736",
"examples/release1/sa/functions/function_sa_audit_thresholds.arcadia": "e5a04325d52183956dca814dd90f4e56c96c6b7db0f4f202f203ecb49c3e0f4f",
"examples/release1/sa/functions/function_sa_restore_work.arcadia": "fddeb67308051325041fee641fe758ddf43345b7c47b66d433616ad07fdccdd6",
"examples/source-project/sa/assurance.arcadia": "ab76044836e4dcd42a82d316846ec87da2108939aa2037640c5bca1d2ecdee0f",
"examples/source-project/sa/participants.arcadia": "1abad579812e77877b45a3d8e3c3e9da734be2d04a0254cc730a5257ebd2dc88",
"examples/source-project/sa/reporting.arcadia": "f0b7443f728912ca163de39b6055876b533a77feaa3219b2d40a2dd65712e058",
"licenses/llvm-libunwind/llvm-ea7d852a70e8-libunwind-LICENSE.TXT": "b5efebcaca80879234098e52d1725e6d9eb8fb96a19fce625d39184b705f7b6d",
"licenses/rust/COPYING.RUNTIME": "28e85c5aa4af9b4f1dfe6b4817aa3eefb3eaaee7fd735045016f29ccf50276a1",
"licenses/rust/COPYING3": "8ceb4b9ee5adedde47b31e975c1d90c73ad27b6b165a1dcd80c7c545eb65b903",
"licenses/rust/COPYRIGHT-library.html": "68129500b616d5838629e68f55ff3aed5e096dacf60ce9eb41bbe599a563afa6",
"licenses/rust/COPYRIGHT.html": "5b0c93fc4e6d4b072eaa521b1762d1e746f4c368f65e81a0e5308e2772dac85e",
"licenses/dependencies/arrayref-0.3.9/LICENSE": "1bc7e6f475b3ec99b7e2643411950ae2368c250dd4c5c325f80f9811362a94a1",
"licenses/dependencies/arrayvec-0.7.8/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/arrayvec-0.7.8/LICENSE-MIT": "4da95ec4ecb65b738d470b7d762894ad9c97da93e6cbfb18b570fc2c96f4b871",
"licenses/dependencies/ash-0.38.0+1.3.281/LICENSE-APACHE": "0e8a410375e1ee5c75c6198b08b534fec6e5edef766cf971bab4a404542636ab",
"licenses/dependencies/ash-0.38.0+1.3.281/LICENSE-MIT": "c733ccf8ab25df175a63d9d844677b98e3a5ab8f8de1c1616087e6868a7f948e",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-THIRD-PARTY": "6226d0632e2e1a80c23597e964da9812ae193c535fe058154afb034e94167aa5",
"licenses/dependencies/autocfg-1.5.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/autocfg-1.5.1/LICENSE-MIT": "27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac",
"licenses/dependencies/axum-0.8.9/LICENSE": "6a13bc24a100a6812f053879ec51b126b103af7cda6dbf48c4188722da44da9f",
"licenses/dependencies/axum-core-0.5.6/LICENSE": "008c87afcd2e626eaf564093250bed06dd7efb5732113264bba3dda8f1c556a1",
"licenses/dependencies/base64-0.22.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/base64-0.22.1/LICENSE-MIT": "0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7",
"licenses/dependencies/bit-set-0.8.0/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/bit-set-0.8.0/LICENSE-MIT": "f51ac2c59a222f7476ce507ca879960e2b64ea64bb2786eefdbeb7b0b538d1b7",
"licenses/dependencies/bit-vec-0.8.0/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/bit-vec-0.8.0/LICENSE-MIT": "f51ac2c59a222f7476ce507ca879960e2b64ea64bb2786eefdbeb7b0b538d1b7",
"licenses/dependencies/bitflags-2.13.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/bitflags-2.13.1/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-APACHE": "e3ba223bb1423f0aad8c3dfce0fe3148db48926d41e6fbc3afbbf5ff9e1c89cb",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-MIT": "9df9ba60a11af705f2e451b53762686e615d86f76b169cf075c3237730dbd7e2",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-ZLIB": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-APACHE": "e3ba223bb1423f0aad8c3dfce0fe3148db48926d41e6fbc3afbbf5ff9e1c89cb",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-MIT": "9df9ba60a11af705f2e451b53762686e615d86f76b169cf075c3237730dbd7e2",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-ZLIB": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/bytes-1.12.1/LICENSE": "45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42",
"licenses/dependencies/cc-1.4.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cc-1.4.5/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/cfg-if-1.0.4/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cfg-if-1.0.4/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/cfg_aliases-0.2.2/LICENSE": "31b94860253d8ec7b4529f51901044d3b459d6292d996504a36b1bae3a36a812",
"licenses/dependencies/chacha20-0.10.2/LICENSE-APACHE": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
"licenses/dependencies/chacha20-0.10.2/LICENSE-MIT": "b8c6939380a400f53e11923d50fcc4dd2fa1ba8339fd9d04cda38a0251b6c9b0",
"licenses/dependencies/codespan-reporting-0.12.0/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/core_maths-0.1.1/LICENSE": "9ebf8c4cc0b735ca13a766451f7b8097db3185975ceb2ba94b5abf439156a91f",
"licenses/dependencies/cosmic-text-0.15.0/LICENSE-APACHE": "000b4962e6b27176a0ff89cce4be555b16472cafb5671eb2804a8fdac6854793",
"licenses/dependencies/cosmic-text-0.15.0/LICENSE-MIT": "95557bafe728379e206f3b6d4aceeaa054d271c71d722411a6222e2dec01138c",
"licenses/dependencies/cpufeatures-0.3.1/LICENSE-APACHE": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
"licenses/dependencies/cpufeatures-0.3.1/LICENSE-MIT": "73b9dc2e79c7308998dd30296e073aefaefb944a68fb89aa412c23c0edcabcaa",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-ZLIB": "b3ec01ad0869c5c50937bc68780cd0bb44e235ad858dfa54a7a381dced9b115a",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-APACHE": "b59affd015e517ed998dd735757f9a3693643cd389609947ed54074234a10784",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-MIT": "c138726a726ac37bae09d0f8a48e74e8e3aa8a8952fcd10fae0fb224cc1c05f1",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-ZLIB": "01e533bd94e8f1c32b2c2531e2c398de7d35d7804add3d574b4e1fe581d53537",
"licenses/dependencies/displaydoc-0.2.7/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/displaydoc-0.2.7/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/document-features-0.2.12/LICENSE-APACHE": "074e6e32c86a4c0ef8b3ed25b721ca23aca83df277cd88106ef7177c354615ff",
"licenses/dependencies/document-features-0.2.12/LICENSE-MIT": "aa893340d14b9844625be6a50ac644169a01b52f0211cbf81b09e1874c8cd81d",
"licenses/dependencies/dpi-0.1.2/LICENSE": "6dc0e068dcf3a5bc8e054205b85b7720e1d49265bbc64bf515d2cf79197df69a",
"licenses/dependencies/dpi-0.1.2/LICENSE-LIBM-MIT": "9eff396a99bafd208e7126602420d6864f6066c08b84485a5b032320a9c01997",
"licenses/dependencies/equivalent-1.0.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/equivalent-1.0.2/LICENSE-MIT": "7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349",
"licenses/dependencies/error-code-3.4.0/LICENSE": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/etagere-0.2.15/LICENSE-APACHE": "2d56a37f3d1e461f6b1539ab94e0e6bcc55443e376098aee85ac3b2890860290",
"licenses/dependencies/etagere-0.2.15/LICENSE-MIT": "9cfc9c9a4608501b5da3746948d2be2dd709ad51f6bcb0c1c685760ee3dde31f",
"licenses/dependencies/euclid-0.22.14/COPYRIGHT": "ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a",
"licenses/dependencies/euclid-0.22.14/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/euclid-0.22.14/LICENSE-MIT": "62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3",
"licenses/dependencies/fastrand-2.5.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/fastrand-2.5.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/find-msvc-tools-0.1.12/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/find-msvc-tools-0.1.12/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/float_next_after-1.0.0/LICENSE": "0604d5817110dacc5c7d9b7de6b58b962794603d4823c357157bd5dec4198bc5",
"licenses/dependencies/foldhash-0.1.5/LICENSE": "b1181a40b2a7b25cf66fd01481713bc1005df082c53ef73e851e55071b102744",
"licenses/dependencies/foldhash-0.2.0/LICENSE": "b1181a40b2a7b25cf66fd01481713bc1005df082c53ef73e851e55071b102744",
"licenses/dependencies/font-types-0.10.1/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/font-types-0.10.1/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/font-types-0.12.4/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/font-types-0.12.4/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/fontdb-0.23.0/LICENSE": "59a1fdac3bd550043599bd159fd70f09a1108c2b09e3751d39b11e1ff8e51f00",
"licenses/dependencies/form_urlencoded-1.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/form_urlencoded-1.2.2/LICENSE-MIT": "20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e",
"licenses/dependencies/futures-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-channel-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-channel-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-core-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-core-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-executor-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-executor-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-io-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-io-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-macro-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-macro-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-sink-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-sink-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-task-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-task-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-util-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-util-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/getrandom-0.2.17/LICENSE-APACHE": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
"licenses/dependencies/getrandom-0.2.17/LICENSE-MIT": "42fa16951ce7f24b5a467a40e5b449a1d41e662f97ca779864f053f39e097737",
"licenses/dependencies/getrandom-0.4.3/LICENSE-APACHE": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
"licenses/dependencies/getrandom-0.4.3/LICENSE-MIT": "523a42c25d245dde9c015f882cec7f4555aad883382a6cf19b4b7d9b2cd5419b",
"licenses/dependencies/glam-0.25.0/LICENSE-APACHE": "be33ddb87a30fd321ab100e2d922cba512e50ec7a63d8e62e5bfc0798dd4b585",
"licenses/dependencies/glam-0.25.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/glow-0.16.0/LICENSE-APACHE": "b8601fc79bdf8d8088f0938bea861ffc63ed0eebbedf25f44ab2cf2e85bd7edc",
"licenses/dependencies/glow-0.16.0/LICENSE-MIT": "cdbd06e25b8c9c5d6019949d2de8123f56d29cee4166396423d2ba8c81700845",
"licenses/dependencies/glow-0.16.0/LICENSE-ZLIB": "636f644f1e149eb62961657c0e34953681eff64435653912e7bd19992666faa5",
"licenses/dependencies/glutin_wgl_sys-0.6.1/LICENSE": "a4445427440043e8ce6fadf7a43fb906cb0d7f6c573a560a9f142cf9f9bf8ff4",
"licenses/dependencies/gpu-allocator-0.27.0/LICENSE-APACHE": "0178e21322b0e88aa3aeb3146f6a9611bc1f8df6d98bdfb34be28b9dd56a8107",
"licenses/dependencies/gpu-allocator-0.27.0/LICENSE-MIT": "ad41be6cc6538b29b9346648f41432b5e460bad6be073b5eeaa41320ea2921dc",
"licenses/dependencies/guillotiere-0.6.2/LICENSE": "7e98bed7f100747aaae7d82ab94fbe6b76fd6b84b09a3aaa413bff8196d0fbb1",
"licenses/dependencies/half-2.7.1/LICENSE-APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/half-2.7.1/LICENSE-MIT": "508a77d2e7b51d98adeed32648ad124b7b30241a8e70b2e72c99f92d8e5874d1",
"licenses/dependencies/harfrust-0.3.2/LICENSE": "7d43d2ef1ce976c7bfb423c696ad9938ccfc31e9ec5be752265e43fe9d29f697",
"licenses/dependencies/hashbrown-0.15.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.15.5/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/hashbrown-0.16.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.16.1/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/hashbrown-0.17.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.17.1/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/http-1.5.0/LICENSE-APACHE": "8bb1b50b0e5c9399ae33bd35fab2769010fa6c14e8860c729a52295d84896b7a",
"licenses/dependencies/http-1.5.0/LICENSE-MIT": "dc91f8200e4b2a1f9261035d4c18c33c246911a6c0f7b543d75347e61b249cff",
"licenses/dependencies/http-body-1.1.0/LICENSE": "248378d0a3383c173fb925f17141b88e71580b3ba17ddc6ac3d2a344683232ab",
"licenses/dependencies/http-body-util-0.1.5/LICENSE": "248378d0a3383c173fb925f17141b88e71580b3ba17ddc6ac3d2a344683232ab",
"licenses/dependencies/httparse-1.10.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/httparse-1.10.1/LICENSE-MIT": "391a5396cec6230bfabd4ef4eb2350eb895bc5efce377a2218f5702ed020d3e3",
"licenses/dependencies/httpdate-1.0.3/LICENSE-APACHE": "4d10fe5f3aa176b05b229a248866bad70b834c173f1252a814ff4748d8a13837",
"licenses/dependencies/httpdate-1.0.3/LICENSE-MIT": "934887691e05d69d7c86ad3f2c360980fa30c15b035e351f3c9865e99da4debc",
"licenses/dependencies/hyper-1.11.1/LICENSE": "2d01890414494742ba4a509fcec8efa40f6d8be22cbd72be7cff08d6fda4ec89",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-ISC": "7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-MIT": "709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c",
"licenses/dependencies/hyper-util-0.1.20/LICENSE": "9e0a97848ea543aef745c98e84fde696a9a3e0735538f6daefdd3cb1942effc1",
"licenses/dependencies/iced-0.14.0/LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/icu_collections-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_locale_core-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_normalizer-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_normalizer_data-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_properties-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_properties_data-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_provider-2.3.1/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/idna-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/idna-1.1.0/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/idna_adapter-1.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/idna_adapter-1.2.2/LICENSE-MIT": "8b43ce8accd61e9d370b5ca9e9c4f953279b5c239926c62315b40e24df51b726",
"licenses/dependencies/indexmap-2.14.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/indexmap-2.14.1/LICENSE-MIT": "ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055",
"licenses/dependencies/ipnet-2.12.1/LICENSE-APACHE": "87d9feb9238c6bd8e0024fc4733b06cff036f89f36d93b7df1c8a0549bbb7a5b",
"licenses/dependencies/ipnet-2.12.1/LICENSE-MIT": "47dc9ff29128ddfb4d6a0435383c9f89120bc374dbcc1dd00b933a0b28aa7865",
"licenses/dependencies/itoa-1.0.18/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/itoa-1.0.18/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/jobserver-0.1.35/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/jobserver-0.1.35/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/khronos-egl-6.0.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/khronos-egl-6.0.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/kurbo-0.10.4/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/kurbo-0.10.4/LICENSE-MIT": "23c23145f6eac25c28cdcc03d38506a5712a9a8cffb5bd5301457f6173ea696e",
"licenses/dependencies/libc-0.2.189/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/libc-0.2.189/LICENSE-MIT": "123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e",
"licenses/dependencies/libloading-0.8.9/LICENSE": "b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f",
"licenses/dependencies/libm-0.2.16/LICENSE.txt": "3823dda7cf046602f4b4e77ec8e227863dc4736037cc85bb33d9f19febe16bb7",
"licenses/dependencies/lilt-0.8.2/LICENSE": "120b2f21f9b9f98ef4159de09f9a55a3afb6733dd1c0b1d9eeec7f136465b2cd",
"licenses/dependencies/linebender_resource_handle-0.1.1/LICENSE-APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/linebender_resource_handle-0.1.1/LICENSE-MIT": "508a77d2e7b51d98adeed32648ad124b7b30241a8e70b2e72c99f92d8e5874d1",
"licenses/dependencies/litemap-0.8.3/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/litrs-1.0.0/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/litrs-1.0.0/LICENSE-MIT": "7dc1552e88f49132cb358b1b962fc5e79fa42d70bcbb88c526d33e45b8e98036",
"licenses/dependencies/lock_api-0.4.14/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/lock_api-0.4.14/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/log-0.4.34/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/log-0.4.34/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/lru-0.16.4/LICENSE": "061dc50af2cd9340703daf61978af3200cf681b12ea67a323c33ba109a23a45e",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-MIT": "1466d9b4f3a59bb8997fc8d5fa977ce3f6a24bb2358793c09bfdf007039f6486",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-ZLIB": "09785877275ffada6c371b652a30e95c26b435126fc0fc62f1bc2d72171f80a4",
"licenses/dependencies/matchit-0.8.4/LICENSE": "de701d0618d694feb1af90f02181a1763d9b0bdeb70a3a592781e529077dba65",
"licenses/dependencies/matchit-0.8.4/LICENSE.httprouter": "162ce11ad71338d0a0c6ebaf5c48af72c6ae237b468859d3656fe2d9ed3f3a85",
"licenses/dependencies/memchr-2.8.3/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/memchr-2.8.3/LICENSE-MIT": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
"licenses/dependencies/memchr-2.8.3/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/memmap2-0.9.11/LICENSE-APACHE": "04ea4849dba9dcae07113850c6f1b1a69052c625210639914eee352023f750ad",
"licenses/dependencies/memmap2-0.9.11/LICENSE-MIT": "0d25d03b5ab49576178ad0cae7a2648d12c17ad0452fe49c07e55e4b59aa5257",
"licenses/dependencies/mime-0.3.17/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/mime-0.3.17/LICENSE-MIT": "df9cfd06d8a44d9a671eadd39ffd97f166481da015a30f45dfd27886209c5922",
"licenses/dependencies/mio-1.2.3/LICENSE": "07919255c7e04793d8ea760d6c2ce32d19f9ff02bdbdde3ce90b1e1880929a9b",
"licenses/dependencies/naga-27.0.3/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/naga-27.0.3/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/num-traits-0.2.19/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/num-traits-0.2.19/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/oa-core-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/oa-desktop-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/oa-server-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/once_cell-1.21.4/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/once_cell-1.21.4/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/ordered-float-5.5.0/LICENSE-MIT": "f7715d38a3fa1b4ac97c5729740752505a39cb92ee83ab5b102aeb5eaa7cdea4",
"licenses/dependencies/parking_lot-0.12.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/parking_lot-0.12.5/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/parking_lot_core-0.9.12/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/parking_lot_core-0.9.12/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/percent-encoding-2.3.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/percent-encoding-2.3.2/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/pin-project-lite-0.2.17/LICENSE-APACHE": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/pin-project-lite-0.2.17/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/pkg-config-0.3.34/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/pkg-config-0.3.34/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/potential_utf-0.1.6/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/presser-0.3.1/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/presser-0.3.1/LICENSE-MIT": "090a294a492ab2f41388252312a65cf2f0e423330b721a68c6665ac64766753b",
"licenses/dependencies/proc-macro2-1.0.107/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/proc-macro2-1.0.107/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/quinn-0.11.11/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-0.11.11/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quinn-proto-0.11.17/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-proto-0.11.17/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quinn-udp-0.5.15/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-udp-0.5.15/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quote-1.0.47/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/quote-1.0.47/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/rand-0.10.2/COPYRIGHT": "90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5",
"licenses/dependencies/rand-0.10.2/LICENSE-APACHE": "35242e7a83f69875e6edeff02291e688c97caafe2f8902e4e19b49d3e78b4cab",
"licenses/dependencies/rand-0.10.2/LICENSE-MIT": "209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b",
"licenses/dependencies/rand_core-0.10.1/COPYRIGHT": "92b81db30f7ab6d693e0af5661a40d273ca1947e891123ed823924192c10cbc7",
"licenses/dependencies/rand_core-0.10.1/LICENSE-APACHE": "6df43f6f4b5d4587f3d8d71e45532c688fd168afa5fe89d571cb32fa09c4ef51",
"licenses/dependencies/rand_core-0.10.1/LICENSE-MIT": "8b6e9feec03e7c9a5facb26855cecd31662bf989b636bcfe79521bdf8ac863f0",
"licenses/dependencies/rand_pcg-0.10.2/COPYRIGHT": "90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5",
"licenses/dependencies/rand_pcg-0.10.2/LICENSE-APACHE": "6df43f6f4b5d4587f3d8d71e45532c688fd168afa5fe89d571cb32fa09c4ef51",
"licenses/dependencies/rand_pcg-0.10.2/LICENSE-MIT": "2234e3cefee876aeb686ad89e978bdb07bf118a1186ab1cf161bcdf69d4b4f57",
"licenses/dependencies/range-alloc-0.1.5/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/range-alloc-0.1.5/LICENSE.MIT": "ba00052102ed87948bb8822d6e1c496260c83042887b22bb5caad922ec025a60",
"licenses/dependencies/rangemap-1.8.0/LICENSE-APACHE": "1c7745cc26c7294bc9dbc883bcd50700b99a8c0f4859bfce84ec555098ce1ab5",
"licenses/dependencies/rangemap-1.8.0/LICENSE-MIT": "29a4c3823ee29ee5a97c145574a1bac20629fd5e6708be1df0d25bab563e093c",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-APACHE.md": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-MIT.md": "9c5a80639a57c1c945570e7ebbca0706305849ce3c098021325cca9db2f7acc4",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-ZLIB.md": "ae895c8576e682f310fb70d93d9f99b1dd82872094c54a8f6cdfe2ca5c2d6ecb",
"licenses/dependencies/read-fonts-0.35.0/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/read-fonts-0.35.0/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/read-fonts-0.41.0/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/read-fonts-0.41.0/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/renderdoc-sys-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/renderdoc-sys-1.1.0/LICENSE-MIT": "24b2f2eff5a7622e87162823e260f00c6dfbce0e26d585d3d28c785f1edc80ed",
"licenses/dependencies/reqwest-0.12.28/LICENSE-APACHE": "751963a8b88c0e3a9f27e98933079fbcf09b9998b2c13ac49c2e4d58444520d6",
"licenses/dependencies/reqwest-0.12.28/LICENSE-MIT": "47d4e1803702728e03d30f8a848ae2249ba274bbd9f8443e803f7924d83cd371",
"licenses/dependencies/rfd-0.15.4/LICENSE": "65fc947f4bac882a2cd104ef73c246b1b037059df9f2b3a58b7f77f0b9e56071",
"licenses/dependencies/ring-0.17.14/LICENSE": "b3d734001a94efff3579978d953391aa7115f877657d25eb54037a43875d078a",
"licenses/dependencies/ring-0.17.14/LICENSE-BoringSSL": "005fc765ddc5115da796cca915baa9557abae13ff35e0a47c47affc56f6c414d",
"licenses/dependencies/ring-0.17.14/LICENSE-other-bits": "f025ccfb7dfb6bdfedc75ca0f67acc69e6fb4998143d834f7c2f38a29989680f",
"licenses/dependencies/rustc-hash-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/rustc-hash-1.1.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/rustc-hash-2.1.3/LICENSE-APACHE": "95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc",
"licenses/dependencies/rustc-hash-2.1.3/LICENSE-MIT": "30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652",
"licenses/dependencies/rustls-0.23.43/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/rustls-0.23.43/LICENSE-ISC": "7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4",
"licenses/dependencies/rustls-0.23.43/LICENSE-MIT": "709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c",
"licenses/dependencies/rustls-pki-types-1.15.1/LICENSE-APACHE": "45fd05c4865e7c350b98ad7ac50e1b15462d49af4a91e9b0c9dd933dc9a69742",
"licenses/dependencies/rustls-pki-types-1.15.1/LICENSE-MIT": "9117d922e667125508dde62b02c1f57ed22f5ad21eb536aa2e2d99e1c796e639",
"licenses/dependencies/rustls-webpki-0.103.15/LICENSE": "5b698ca13897be3afdb7174256fa1574f8c6892b8bea1a66dd6469d3fe27885a",
"licenses/dependencies/ryu-1.0.23/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/ryu-1.0.23/LICENSE-BOOST": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/same-file-1.0.6/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/same-file-1.0.6/LICENSE-MIT": "cb3c929a05e6cbc9de9ab06a4c57eeb60ca8c724bef6c138c87d3a577e27aa14",
"licenses/dependencies/same-file-1.0.6/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/scopeguard-1.2.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/scopeguard-1.2.0/LICENSE-MIT": "fb77f0a9c53e473abe5103c8632ef9f0f2874d4fb3f17cb2d8c661aab9cee9d7",
"licenses/dependencies/self_cell-1.3.0/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/self_cell-1.3.0/LICENSE-GPLv2": "f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505",
"licenses/dependencies/serde-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_core-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_core-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_derive-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_derive-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_json-1.0.151/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_json-1.0.151/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_path_to_error-0.1.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_path_to_error-0.1.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_urlencoded-0.7.1/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_urlencoded-0.7.1/LICENSE-MIT": "b9eb266294324f672cbe945fe8f2e32f85024f0d61a1a7d14382cdde0ac44769",
"licenses/dependencies/sha1_smol-1.0.1/LICENSE": "282a21b0710441c364025461a447362daf18f5798a7b72ae2f801a2aa536da51",
"licenses/dependencies/shlex-2.0.1/LICENSE-APACHE": "553fffcd9b1cb158bc3e9edc35da85ca5c3b3d7d2e61c883ebcfa8a65814b583",
"licenses/dependencies/shlex-2.0.1/LICENSE-MIT": "4455bf75a91154108304cb283e0fea9948c14f13e20d60887cf2552449dea3b1",
"licenses/dependencies/skrifa-0.37.0/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/skrifa-0.37.0/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/skrifa-0.44.0/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/skrifa-0.44.0/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/slab-0.4.12/LICENSE": "8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18",
"licenses/dependencies/slotmap-1.1.1/LICENSE": "6cec81441b2ab2b5090954c1fb5d0bcca81b86487b5849061fa8952d20ef67d4",
"licenses/dependencies/smallvec-1.16.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/smallvec-1.16.0/LICENSE-MIT": "0b28172679e0009b655da42797c03fd163a3379d5cfa67ba1f1655e974a2a1a9",
"licenses/dependencies/smol_str-0.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/smol_str-0.2.2/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/socket2-0.6.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/socket2-0.6.5/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/softbuffer-0.4.8/LICENSE-APACHE": "a4445427440043e8ce6fadf7a43fb906cb0d7f6c573a560a9f142cf9f9bf8ff4",
"licenses/dependencies/softbuffer-0.4.8/LICENSE-MIT": "0463bfa47d6d763d8c824333efb0e6d6df3946c13c3b077c78ed9f23ca50d0f2",
"licenses/dependencies/stable_deref_trait-1.2.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/stable_deref_trait-1.2.1/LICENSE-MIT": "5e05b024f653a5ce199e77cbbbd42fb5553562ec714b819421ed0c3e552a75d7",
"licenses/dependencies/static_assertions-1.1.0/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/static_assertions-1.1.0/LICENSE-MIT": "ea084a2373ebc1f0902c09266e7bf25a05ab3814c1805bb017ffa7308f90c061",
"licenses/dependencies/strict-num-0.1.1/LICENSE": "3085885678bb161f6c472bbd331f66a2550b555eb76128f7f8247779128199c0",
"licenses/dependencies/subtle-2.6.1/LICENSE": "d1fc1bc0d155df60b2e7705b6b2ae02a05c96f948e1cec6e2fb86360b09f346b",
"licenses/dependencies/swash-0.2.10/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/swash-0.2.10/LICENSE-MIT": "122dadfc2eb4de0f4bafcd9eb4e7502cfe338a7965ebd1d18708cc5050f43f76",
"licenses/dependencies/syn-2.0.119/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/syn-2.0.119/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/syn-3.0.5/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/syn-3.0.5/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/sync_wrapper-1.0.2/LICENSE": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/synstructure-0.13.2/LICENSE": "219920e865eee70b7dcfc948a86b099e7f4fe2de01bcca2ca9a20c0a033f2b59",
"licenses/dependencies/sys-locale-0.3.2/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/sys-locale-0.3.2/LICENSE-MIT": "5cc390ab5e5e6507f467368cbab1297552d64bfd863f4b496c7928508bcfefd8",
"licenses/dependencies/tempfile-3.27.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/tempfile-3.27.0/LICENSE-MIT": "8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36",
"licenses/dependencies/termcolor-1.4.1/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/termcolor-1.4.1/LICENSE-MIT": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
"licenses/dependencies/termcolor-1.4.1/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/thiserror-1.0.69/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-1.0.69/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-2.0.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-2.0.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-impl-1.0.69/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-impl-1.0.69/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-impl-2.0.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-impl-2.0.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/tiny-skia-0.11.4/LICENSE": "6d41e05f1d54fe726997cb0334ec539f1dff50600b1d5d90462ec2b392770ced",
"licenses/dependencies/tiny-skia-path-0.11.4/LICENSE": "6d41e05f1d54fe726997cb0334ec539f1dff50600b1d5d90462ec2b392770ced",
"licenses/dependencies/tinystr-0.8.4/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-APACHE.md": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-MIT.md": "fd80a26fbb3f644af1fa994134446702932968519797227e07a1368dea80f0bc",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-ZLIB.md": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-APACHE.md": "4f44572785f35152c1fd2eadf565b7e079c0f300b4324f0af653419f9d76b735",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-MIT.md": "1dd8eca0f83669e75fa119e34fb9e1be9d16e3e9b6368962b8019db6e8ae5f7b",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-ZLIB.md": "41ace205715d9f19a3214218cc1c01d57c533e02cd0fef7c8e51a49a7fce5ac5",
"licenses/dependencies/tokio-1.53.1/LICENSE": "253cd04c6714889df2d32f3f64d669179a1c95c76ac43c40882c52eb06bc3552",
"licenses/dependencies/tokio-macros-2.7.2/LICENSE": "0b83dc40cba89b9922bb84b0a9c7d2768ce37c1d7e138b7424fd4549915778c9",
"licenses/dependencies/tokio-rustls-0.26.5/LICENSE-APACHE": "cc117d90b498b32b11a886f279b359da16a73c3b01efbb2f5cc004b20262334e",
"licenses/dependencies/tokio-rustls-0.26.5/LICENSE-MIT": "e20fa2b8e0a2565f24a792b94b4bf4b6c2b9d36f781d8a9516e218a036e6677a",
"licenses/dependencies/tower-0.5.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tower-http-0.6.11/LICENSE": "5049cf464977eff4b4fcfa7988d84e74116956a3eb9d5f1d451b3f828f945233",
"licenses/dependencies/tower-layer-0.3.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tower-service-0.3.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tracing-0.1.44/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/tracing-attributes-0.1.31/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/tracing-core-0.1.36/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/try-lock-0.2.5/LICENSE": "c816a0749cdc6bf062a5111c159723de51b2bfac66a1dac2655abd9e6b1583eb",
"licenses/dependencies/ttf-parser-0.25.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/ttf-parser-0.25.1/LICENSE-MIT": "f3c9fe731c701ed77fd5fbaac573872af04dc5869385eb9bd5e3c73c42713814",
"licenses/dependencies/unicode-bidi-0.3.18/COPYRIGHT": "edb20b474f6cbd4f4db066b54a9e0f687d0009d309412a63431189b59b8e2a07",
"licenses/dependencies/unicode-bidi-0.3.18/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-bidi-0.3.18/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-UNICODE": "f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1",
"licenses/dependencies/unicode-linebreak-0.1.5/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/unicode-script-0.5.8/LICENSE-APACHE": "7cbb56d1b5d83d735056b363ab20958524120afafc4ad8206e6be98cdec5d737",
"licenses/dependencies/unicode-script-0.5.8/LICENSE-MIT": "7ad3ea8ca3caf894db98c3f31d5d4949173ffa93c883ef19a9e529ad48960f8c",
"licenses/dependencies/unicode-segmentation-1.13.3/COPYRIGHT": "23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d",
"licenses/dependencies/unicode-segmentation-1.13.3/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-segmentation-1.13.3/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/unicode-width-0.2.2/COPYRIGHT": "23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d",
"licenses/dependencies/unicode-width-0.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-width-0.2.2/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/untrusted-0.9.0/LICENSE.txt": "7abd9b6960dcf7d4d0a48606a5b71bfe37d472db68d70637f3a58a56785f1621",
"licenses/dependencies/url-2.5.8/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/url-2.5.8/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/utf8_iter-1.0.4/COPYRIGHT": "c30152c94a6d75e021adbc52b3a52470366a46edb917e17deae3259251af244c",
"licenses/dependencies/utf8_iter-1.0.4/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/utf8_iter-1.0.4/LICENSE-MIT": "3fa4ca83dcc9237839b1bdeb2e6d16bdfb5ec0c5ce42b24694d8bbf0dcbef72c",
"licenses/dependencies/uuid-1.26.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/uuid-1.26.0/LICENSE-MIT": "436bc5a105d8e57dcd8778730f3754f7bf39c14d2f530e4cde4bd2d17a83ec3d",
"licenses/dependencies/version_check-0.9.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/version_check-0.9.5/LICENSE-MIT": "b7e650f3fce5c53249d1cdc608b54df156a97edd636cf9d23498d0cfe7aec63e",
"licenses/dependencies/want-0.3.1/LICENSE": "a65f5d0a945d267751344c95665945b90c030ea107faf5c85d518929886187da",
"licenses/dependencies/web-time-1.1.0/LICENSE-APACHE": "54a744942eb3fa63a74d8d359989ed6962c04f3f10ff20cfa08ff8aa7efbe4e6",
"licenses/dependencies/web-time-1.1.0/LICENSE-MIT": "f428305bbf2e70fbd807af0f3c7ac1b7acfb95311640f451e9d2e48db6d7e96b",
"licenses/dependencies/webpki-roots-1.0.9/LICENSE": "e271993808fec50ab29350b39539cdec611a9103f827e0aa26d61da70e2d33f8",
"licenses/dependencies/wgpu-27.0.1/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-27.0.1/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-core-27.0.3/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-core-27.0.3/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-core-deps-windows-linux-android-27.0.0/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-core-deps-windows-linux-android-27.0.0/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-hal-27.0.4/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-hal-27.0.4/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-types-27.0.1/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-types-27.0.1/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/winapi-util-0.1.11/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/winapi-util-0.1.11/LICENSE-MIT": "cb3c929a05e6cbc9de9ab06a4c57eeb60ca8c724bef6c138c87d3a577e27aa14",
"licenses/dependencies/winapi-util-0.1.11/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/windows-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-core-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-core-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-implement-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-implement-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-interface-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-interface-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-link-0.2.1/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-link-0.2.1/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-result-0.2.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-result-0.2.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-strings-0.1.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-strings-0.1.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.52.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.52.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.59.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.59.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.61.2/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.61.2/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-targets-0.52.6/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-targets-0.52.6/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows_x86_64_gnullvm-0.52.6/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows_x86_64_gnullvm-0.52.6/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/window_clipboard-0.5.1/LICENSE": "7faec985f3e9b1c4a1df646bfedc304ba67e409447f7ab7f4f591f68708d85dc",
"licenses/dependencies/winit-0.30.13/LICENSE": "6dc0e068dcf3a5bc8e054205b85b7720e1d49265bbc64bf515d2cf79197df69a",
"licenses/dependencies/writeable-0.6.4/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/xml-rs-0.8.29/LICENSE": "0dc18d924dc0a5f41172a393012843a5eaaef338e795b3645da9cc3b6068220b",
"licenses/dependencies/yazi-0.2.1/LICENSE-APACHE": "7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c",
"licenses/dependencies/yazi-0.2.1/LICENSE-MIT": "df62e3ef3f207c91073fedd78b4156a278681d0dd3f942379242c62c6a71a3ec",
"licenses/dependencies/yoke-0.8.3/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/yoke-derive-0.8.2/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zeno-0.3.3/LICENSE-APACHE": "7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c",
"licenses/dependencies/zeno-0.3.3/LICENSE-MIT": "34dff8202d63e6df022f4f0ce88dab24f254c35ee0d5958b74dcf74d9eae21cc",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-APACHE": "9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-BSD": "83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-MIT": "1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-APACHE": "9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-BSD": "83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-MIT": "1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df",
"licenses/dependencies/zerofrom-0.1.8/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerofrom-derive-0.1.7/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zeroize-1.9.0/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/zeroize-1.9.0/LICENSE-MIT": "8c7516d4b27b1e495be5e38b612298b63de48d05f49cdac94f70f3cd70f8864b",
"licenses/dependencies/zerotrie-0.2.5/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerovec-0.11.8/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerovec-derive-0.11.6/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zmij-1.0.23/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/clipboard-win-5.4.1/supplement/DoumanAsh-clipboard-win-3b27cf2bfd1a-LICENSE": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/cosmic-text-0.15.0/fonts/FiraMono-LICENSE": "587dd9548304fd421cd254f7550bd101c1250ffc95417f2f7f92d55b44ecbe53",
"licenses/dependencies/cosmic-text-0.15.0/fonts/Inter-LICENSE": "3c8d13d97ea5eb62868833a377034c6be6a9833e768d32abec2a767a8101e4bc",
"licenses/dependencies/cosmic-text-0.15.0/fonts/NotoSans-LICENSE": "5ec4347054089def6904da61d04f0360968f9ef36634b1fe007a5b6ec2f7aa96",
"licenses/dependencies/fontdb-0.23.0/tests/fonts/LICENSE.txt": "b84fdd2c3da5db56385cdbb639795e90aa3e035c53bc3591135f18df3331451f",
"licenses/dependencies/gl_generator-0.14.0/supplement/brendanzab-gl-rs-ea503e8d5fb6-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/gpu-alloc-0.6.2/supplement/zakarumych-gpu-alloc-61020bdcb4eb-COPYING": "12121dfa588677007848ab922a45a1e3248868f6ff063598fceb3141d7897314",
"licenses/dependencies/gpu-alloc-types-0.3.1/supplement/zakarumych-gpu-alloc-7ddd1fe576fc-COPYING": "12121dfa588677007848ab922a45a1e3248868f6ff063598fceb3141d7897314",
"licenses/dependencies/gpu-descriptor-0.3.2/supplement/zakarumych-gpu-descriptor-bb28b4e55b74-COPYING": "f72143f7e9d9fb8bd336b139fa22f825a299591c29f2f7338c5566347b137613",
"licenses/dependencies/gpu-descriptor-types-0.2.0/supplement/zakarumych-gpu-descriptor-9f2fb9546591-COPYING": "f72143f7e9d9fb8bd336b139fa22f825a299591c29f2f7338c5566347b137613",
"licenses/dependencies/harfrust-0.3.2/scripts/ms-use/COPYING": "9906940f61b1f0b533fa7d99baf55178b2808fbe113ea51dfbfad8572ccd5f2b",
"licenses/dependencies/hexf-parse-0.2.1/supplement/CC0-1.0.txt": "a2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499",
"licenses/dependencies/hexf-parse-0.2.1/supplement/hexf-parse-0.2.1-Cargo.toml": "4a56dbdbc12054fd33b7a2634a45cbbe6fe12f5e6f4081002cbfa527f7220c70",
"licenses/dependencies/iced_core-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_core-0.14.0/src/layout/DRUID_LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/iced_debug-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_futures-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_graphics-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_graphics-0.14.0/assets/FiraSans-Regular.ttf/Fira-OFL.txt": "99bfb7c1e845b79d1031fcf37e678178eb4a8c7cc74a3f218ddf7223083a6fcd",
"licenses/dependencies/iced_graphics-0.14.0/assets/FiraSans-Regular.ttf/FiraSans-Regular-NOTICE.txt": "1e0baaa389b1647d06322ac9ea37822f31995408200ae5a2805a6b9bea0810d1",
"licenses/dependencies/iced_graphics-0.14.0/assets/Iced-Icons.ttf/Iced-Icons-NOTICE.txt": "8175634e30f84ef72a24c4965fb0e87f45a3c1274cc0e79e0473af582cffd1c4",
"licenses/dependencies/iced_graphics-0.14.0/assets/Iced-Icons.ttf/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_program-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_renderer-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_runtime-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_tiny_skia-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_wgpu-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_widget-0.14.2/supplement/iced-rs-iced-54abf81d13fe-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_winit-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/khronos_api-3.1.0/supplement/brendanzab-gl-rs-f150967b1c44-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/lyon-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_algorithms-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_algorithms-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_geom-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_geom-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_path-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_path-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_tessellation-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_tessellation-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/profiling-1.0.18/supplement/aclysma-profiling-8271551172eb-LICENSE-APACHE": "10d30a673cd5e9349bdc02aeb48f14b3386d27d0da32df8f0a555d4aa16aa551",
"licenses/dependencies/profiling-1.0.18/supplement/aclysma-profiling-8271551172eb-LICENSE-MIT": "c8167fdeeed46d3f244d3f85c5bf998ce889343691c32be2c61a8bc4b5c08333",
"licenses/dependencies/ring-0.17.14/src/polyfill/once_cell/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/ring-0.17.14/src/polyfill/once_cell/LICENSE-MIT": "6ee2ed6c77710de911761acd5fc1ad1da00f476beb1a7ef27e78c2d1858deafc",
"licenses/dependencies/ring-0.17.14/third_party/fiat/LICENSE": "9eacbcb81be660840c714a560a9d65ba07913db98dd4baf969f78dd499fdd60f",
"licenses/dependencies/spirv-0.3.0+sdk-1.3.268.0/supplement/gfx-rs-rspirv-e91a5debc10c-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/svg_fmt-0.4.5/supplement/nical-rust_debug-93f414cd572b-LICENSE": "7e98bed7f100747aaae7d82ab94fbe6b76fd6b84b09a3aaa413bff8196d0fbb1",
"licenses/dependencies/tracing-core-0.1.36/src/spin/LICENSE": "58545fed1565e42d687aecec6897d35c6d37ccb71479a137c0deb2203e125c79",
"licenses/dependencies/ttf-parser-0.25.1/tests/fonts/colr_1_LICENSE": "58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd"
}
@@ -0,0 +1,7 @@
{
"added": {
"%SystemDrive%/ProgramData/Microsoft/Windows/Caches/cversions.2.db": "6b4f0b9a1cae97c1e5c355bffbe77b76ce6a65564dfb819f57285d6604f4137f"
},
"removed": [],
"changed": {}
}
@@ -0,0 +1,6 @@
{
"atUtc": "2026-09-11T16:25:37.6853748+00:00",
"action": "Created missing Desktop directory inside the private native-test profile",
"reason": "Windows Open dialog reported the private USERPROFILE/Desktop location unavailable",
"packageModified": false
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

@@ -0,0 +1,65 @@
# Packaged contextual authoring — native Windows acceptance
Codex-9e8r6t `/root`, 2026-09-11. **Fresh corrected-profile trial pending.**
The first trial below established desktop/model behavior but failed the strict
package-file inventory guard because the test launcher omitted a Windows path
environment variable. No release has been published from this evidence yet.
Linux remains paused by the user.
## Frozen package and first native trial
The independent review admitted the exact 559-file ZIP, 32,775,691 bytes,
SHA256 `9186d4fc9a7b52fb195c183c4847c8e3419ea6da8b3f907e0c06f9ceec58dee0`.
Root launched its independent extraction at 16:22:25 UTC, PID9764, using
GUI5657 and F456 runtime, a new private application profile and
`PATH=C:\Windows\System32;C:\Windows`. Full process environment and executable
paths are recorded in `.local/contextual-prerelease-gui-20260911/launch.json`.
The only loaded modules outside C:\Windows were the packaged executable and
its sibling libunwind.dll. No compiler or toolchain runtime path was needed.
The Home page opened with an empty Recent models list. The built-in Engineering
guide rendered its offline topics and first-model instructions. Through the real
Open picker, root loaded a private complete two-file contextual-source baseline,
then used Behavior → Add first lifeline. Parent name `Assessment lifeline` and
new root Activity `Assess incident work` remained independent; the source form
showed the retained consumer and explicit OA root. Use returned to the pending
parent with two accepted objects. Root clicked Create before Save; the canvas
and tree then showed the Activity and its lifeline with four accepted objects.
Ctrl+S displayed All changes saved.
The unchanged complete model/source oracle subsequently passed this first
trial's **model-only** check: three exact reachable/physical source files and
original role UUIDs. This does not waive the separate package-inventory failure.
Screenshots, exact checkpoint, oracle output/arguments and raw process logs
remain in the first trial. Native Alt+F4 closed PID9764 normally; a subsequent
process check found it absent. A numeric GUI exit code was not observed.
## Test-environment correction and preserved failure
The custom USERPROFILE initially had no Desktop directory. Windows Open showed
a Location is not available notice for that private path. Root created only
that missing directory inside the private trial profile and dismissed the notice
with Escape. The first accessibility-index click did not dismiss it; a later
set_value attempt returned `Requested property was not in the CacheRequest`.
After refreshing, ordinary literal typing into the visibly focused file-name
field opened the intended private model. No model-path shortcut or implicit
source modification was substituted.
After GUI Save, the strict package guard refused **before** running its saved
checkpoint oracle. Exact comparison found no removed or changed original file,
but one new file at the literal relative path
`%SystemDrive%/ProgramData/Microsoft/Windows/Caches/cversions.2.db`.
The launcher omitted SystemDrive; this is the identified environment hypothesis
for Windows shell cache placement, to be tested by a fresh corrected trial.
The extra file, first extraction and first trial are preserved. They are not
cleaned or relabeled as an unchanged-package pass. The later explicitly scoped
model-only oracle check above was recorded separately.
The corrected launcher will retain private APPDATA/LOCALAPPDATA/USERPROFILE and
TEMP/TMP, create Desktop before launch, and supply standard Windows path
environment variables without inheriting credentials or toolchain PATH. A fresh
extraction must repeat desktop opening, guide, real contextual Create/Save and
the unchanged complete oracle, then preserve all 559 original package files
with no additions. Root owns that native acceptance and publication; the server
reviewer's earlier artifact/API/persistence results remain separate and valid
for their recorded pre-GUI scope.
@@ -0,0 +1,10 @@
{
"atUtc": "2026-09-11T16:36:53.669982+00:00",
"args": [
"same",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\harness\\fixtures\\staged-source-authoring\\base\\project.arcadia",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\work\\project.arcadia"
],
"exitCode": 0,
"oracleSha256": "967d9ba3c6fb3a7efb410833903ec94556ca2d48a67d5072c8bb160f40a00f9c"
}
@@ -0,0 +1 @@
PASS exact model/identity/2 reachable sources; 2 exact disk files (0 proven retained)
@@ -0,0 +1 @@
// Preserve this independent engineering note: secours 雨 Δ.
@@ -0,0 +1,7 @@
oa_activity assess_incident_work "Assess incident work" id "6073e5c2-f8ec-4d2e-a1b3-a5003d0553f2" {
description "";
parent none;
}
@@ -0,0 +1,25 @@
arcadia 7;
project contextual_source_acceptance "Contextual source acceptance" id "d1510000-0000-4000-8000-000000000001" {
include "notes.arcadia";
// The viewpoint is explicit before any lifeline exists.
oa_scenario operational_assessment "Operational assessment" id "d1510000-0000-4000-8000-000000000002" {
viewpoint OperationalActivity;
steps [];
oa_lifeline assessment_lifeline "Assessment lifeline" id "b5018105-0708-4077-9d74-98643d5936aa" {
description "";
represented @assess_incident_work;
}
}
// Contributions are occurrences; root Functions are separate sources.
sa_functional_chain system_assessment "System assessment" id "d1510000-0000-4000-8000-000000000003" {
steps [];
}
include "oa/activities/activity_assess_incident_work.arcadia";
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

@@ -0,0 +1,23 @@
{
"atUtc": "2026-09-11T16:36:54.068996+00:00",
"pid": 6344,
"package": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-extraction2-20260911\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm",
"environment": {
"SystemRoot": "C:\\Windows",
"SystemDrive": "C:",
"ProgramData": "C:\\ProgramData",
"ALLUSERSPROFILE": "C:\\ProgramData",
"PUBLIC": "C:\\Users\\Public",
"WINDIR": "C:\\Windows",
"PATH": "C:\\Windows\\System32;C:\\Windows",
"USERPROFILE": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\profile",
"LOCALAPPDATA": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\profile\\local",
"APPDATA": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\profile\\roaming",
"TEMP": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\tmp",
"TMP": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\tmp"
},
"reviewSha256": "3a6bf2580b25dad696d635dcbbde88522a065f83698229c2a22dda92f2ab6ee8",
"archiveSha256": "9186d4fc9a7b52fb195c183c4847c8e3419ea6da8b3f907e0c06f9ceec58dee0",
"source": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\work\\project.arcadia",
"scope": "Fresh extracted package; native acceptance pending"
}
@@ -0,0 +1,506 @@
[
{
"ModuleName": "arcadia-studio.exe",
"FileName": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-extraction2-20260911\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm\\arcadia-studio.exe"
},
{
"ModuleName": "ntdll.dll",
"FileName": "C:\\Windows\\SYSTEM32\\ntdll.dll"
},
{
"ModuleName": "KERNEL32.DLL",
"FileName": "C:\\Windows\\System32\\KERNEL32.DLL"
},
{
"ModuleName": "KERNELBASE.dll",
"FileName": "C:\\Windows\\System32\\KERNELBASE.dll"
},
{
"ModuleName": "apphelp.dll",
"FileName": "C:\\Windows\\SYSTEM32\\apphelp.dll"
},
{
"ModuleName": "user32.dll",
"FileName": "C:\\Windows\\System32\\user32.dll"
},
{
"ModuleName": "win32u.dll",
"FileName": "C:\\Windows\\System32\\win32u.dll"
},
{
"ModuleName": "GDI32.dll",
"FileName": "C:\\Windows\\System32\\GDI32.dll"
},
{
"ModuleName": "gdi32full.dll",
"FileName": "C:\\Windows\\System32\\gdi32full.dll"
},
{
"ModuleName": "msvcp_win.dll",
"FileName": "C:\\Windows\\System32\\msvcp_win.dll"
},
{
"ModuleName": "ucrtbase.dll",
"FileName": "C:\\Windows\\System32\\ucrtbase.dll"
},
{
"ModuleName": "ole32.dll",
"FileName": "C:\\Windows\\System32\\ole32.dll"
},
{
"ModuleName": "combase.dll",
"FileName": "C:\\Windows\\System32\\combase.dll"
},
{
"ModuleName": "RPCRT4.dll",
"FileName": "C:\\Windows\\System32\\RPCRT4.dll"
},
{
"ModuleName": "advapi32.dll",
"FileName": "C:\\Windows\\System32\\advapi32.dll"
},
{
"ModuleName": "msvcrt.dll",
"FileName": "C:\\Windows\\System32\\msvcrt.dll"
},
{
"ModuleName": "sechost.dll",
"FileName": "C:\\Windows\\System32\\sechost.dll"
},
{
"ModuleName": "bcryptprimitives.dll",
"FileName": "C:\\Windows\\System32\\bcryptprimitives.dll"
},
{
"ModuleName": "shell32.dll",
"FileName": "C:\\Windows\\System32\\shell32.dll"
},
{
"ModuleName": "imm32.dll",
"FileName": "C:\\Windows\\System32\\imm32.dll"
},
{
"ModuleName": "ws2_32.dll",
"FileName": "C:\\Windows\\System32\\ws2_32.dll"
},
{
"ModuleName": "oleaut32.dll",
"FileName": "C:\\Windows\\System32\\oleaut32.dll"
},
{
"ModuleName": "libunwind.dll",
"FileName": "C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-extraction2-20260911\\ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm\\libunwind.dll"
},
{
"ModuleName": "bcrypt.dll",
"FileName": "C:\\Windows\\SYSTEM32\\bcrypt.dll"
},
{
"ModuleName": "dwmapi.dll",
"FileName": "C:\\Windows\\SYSTEM32\\dwmapi.dll"
},
{
"ModuleName": "uxtheme.dll",
"FileName": "C:\\Windows\\SYSTEM32\\uxtheme.dll"
},
{
"ModuleName": "opengl32.dll",
"FileName": "C:\\Windows\\SYSTEM32\\opengl32.dll"
},
{
"ModuleName": "GLU32.dll",
"FileName": "C:\\Windows\\SYSTEM32\\GLU32.dll"
},
{
"ModuleName": "CRYPTBASE.DLL",
"FileName": "C:\\Windows\\SYSTEM32\\CRYPTBASE.DLL"
},
{
"ModuleName": "dxcore.dll",
"FileName": "C:\\Windows\\SYSTEM32\\dxcore.dll"
},
{
"ModuleName": "MSCTF.dll",
"FileName": "C:\\Windows\\System32\\MSCTF.dll"
},
{
"ModuleName": "kernel.appcore.dll",
"FileName": "C:\\Windows\\SYSTEM32\\kernel.appcore.dll"
},
{
"ModuleName": "clbcatq.dll",
"FileName": "C:\\Windows\\System32\\clbcatq.dll"
},
{
"ModuleName": "dataexchange.dll",
"FileName": "C:\\Windows\\system32\\dataexchange.dll"
},
{
"ModuleName": "twinapi.appcore.dll",
"FileName": "C:\\Windows\\system32\\twinapi.appcore.dll"
},
{
"ModuleName": "explorerframe.dll",
"FileName": "C:\\Windows\\system32\\explorerframe.dll"
},
{
"ModuleName": "SHCORE.dll",
"FileName": "C:\\Windows\\System32\\SHCORE.dll"
},
{
"ModuleName": "SHLWAPI.dll",
"FileName": "C:\\Windows\\System32\\SHLWAPI.dll"
},
{
"ModuleName": "Windows.Storage.dll",
"FileName": "C:\\Windows\\System32\\Windows.Storage.dll"
},
{
"ModuleName": "powrprof.dll",
"FileName": "C:\\Windows\\SYSTEM32\\powrprof.dll"
},
{
"ModuleName": "UMPDC.dll",
"FileName": "C:\\Windows\\SYSTEM32\\UMPDC.dll"
},
{
"ModuleName": "CFGMGR32.dll",
"FileName": "C:\\Windows\\SYSTEM32\\CFGMGR32.dll"
},
{
"ModuleName": "dxgi.dll",
"FileName": "C:\\Windows\\system32\\dxgi.dll"
},
{
"ModuleName": "windows.staterepositorycore.dll",
"FileName": "C:\\Windows\\SYSTEM32\\windows.staterepositorycore.dll"
},
{
"ModuleName": "directxdatabasehelper.dll",
"FileName": "C:\\Windows\\SYSTEM32\\directxdatabasehelper.dll"
},
{
"ModuleName": "d3d12.dll",
"FileName": "C:\\Windows\\SYSTEM32\\d3d12.dll"
},
{
"ModuleName": "d3dcompiler_47.dll",
"FileName": "C:\\Windows\\SYSTEM32\\d3dcompiler_47.dll"
},
{
"ModuleName": "cryptsp.dll",
"FileName": "C:\\Windows\\SYSTEM32\\cryptsp.dll"
},
{
"ModuleName": "vm3dgl64.dll",
"FileName": "C:\\Windows\\System32\\DriverStore\\FileRepository\\vm3d.inf_amd64_39d3dfd189710365\\vm3dgl64.dll"
},
{
"ModuleName": "vm3dglhelper64.dll",
"FileName": "C:\\Windows\\System32\\DriverStore\\FileRepository\\vm3d.inf_amd64_39d3dfd189710365\\vm3dglhelper64.dll"
},
{
"ModuleName": "WINMM.dll",
"FileName": "C:\\Windows\\SYSTEM32\\WINMM.dll"
},
{
"ModuleName": "D3D12Core.dll",
"FileName": "C:\\Windows\\SYSTEM32\\D3D12Core.dll"
},
{
"ModuleName": "d3d10warp.dll",
"FileName": "C:\\Windows\\SYSTEM32\\d3d10warp.dll"
},
{
"ModuleName": "D3DSCache.dll",
"FileName": "C:\\Windows\\SYSTEM32\\D3DSCache.dll"
},
{
"ModuleName": "USERENV.dll",
"FileName": "C:\\Windows\\SYSTEM32\\USERENV.dll"
},
{
"ModuleName": "dxilconv.dll",
"FileName": "C:\\Windows\\SYSTEM32\\dxilconv.dll"
},
{
"ModuleName": "dcomp.dll",
"FileName": "C:\\Windows\\SYSTEM32\\dcomp.dll"
},
{
"ModuleName": "Microsoft.Internal.WarpPal.dll",
"FileName": "C:\\Windows\\SYSTEM32\\Microsoft.Internal.WarpPal.dll"
},
{
"ModuleName": "textinputframework.dll",
"FileName": "C:\\Windows\\SYSTEM32\\textinputframework.dll"
},
{
"ModuleName": "uiautomationcore.dll",
"FileName": "C:\\Windows\\SYSTEM32\\uiautomationcore.dll"
},
{
"ModuleName": "OLEACC.dll",
"FileName": "C:\\Windows\\SYSTEM32\\OLEACC.dll"
},
{
"ModuleName": "threadpoolwinrt.dll",
"FileName": "C:\\Windows\\System32\\threadpoolwinrt.dll"
},
{
"ModuleName": "DUI70.dll",
"FileName": "C:\\Windows\\System32\\DUI70.dll"
},
{
"ModuleName": "Comctl32.dll",
"FileName": "C:\\Windows\\WinSxS\\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.26100.8457_none_3e0b2faee331e92d\\Comctl32.dll"
},
{
"ModuleName": "DUser.dll",
"FileName": "C:\\Windows\\System32\\DUser.dll"
},
{
"ModuleName": "CoreMessaging.dll",
"FileName": "C:\\Windows\\SYSTEM32\\CoreMessaging.dll"
},
{
"ModuleName": "CoreUIComponents.dll",
"FileName": "C:\\Windows\\SYSTEM32\\CoreUIComponents.dll"
},
{
"ModuleName": "wintypes.dll",
"FileName": "C:\\Windows\\SYSTEM32\\wintypes.dll"
},
{
"ModuleName": "TextShaping.dll",
"FileName": "C:\\Windows\\SYSTEM32\\TextShaping.dll"
},
{
"ModuleName": "edputil.dll",
"FileName": "C:\\Windows\\SYSTEM32\\edputil.dll"
},
{
"ModuleName": "WindowsCodecs.dll",
"FileName": "C:\\Windows\\SYSTEM32\\WindowsCodecs.dll"
},
{
"ModuleName": "profapi.dll",
"FileName": "C:\\Windows\\System32\\profapi.dll"
},
{
"ModuleName": "thumbcache.dll",
"FileName": "C:\\Windows\\System32\\thumbcache.dll"
},
{
"ModuleName": "policymanager.dll",
"FileName": "C:\\Windows\\SYSTEM32\\policymanager.dll"
},
{
"ModuleName": "Windows.Globalization.dll",
"FileName": "C:\\Windows\\System32\\Windows.Globalization.dll"
},
{
"ModuleName": "globinputhost.dll",
"FileName": "C:\\Windows\\SYSTEM32\\globinputhost.dll"
},
{
"ModuleName": "Bcp47Langs.dll",
"FileName": "C:\\Windows\\SYSTEM32\\Bcp47Langs.dll"
},
{
"ModuleName": "PROPSYS.dll",
"FileName": "C:\\Windows\\System32\\PROPSYS.dll"
},
{
"ModuleName": "urlmon.dll",
"FileName": "C:\\Windows\\System32\\urlmon.dll"
},
{
"ModuleName": "iertutil.dll",
"FileName": "C:\\Windows\\System32\\iertutil.dll"
},
{
"ModuleName": "srvcli.dll",
"FileName": "C:\\Windows\\System32\\srvcli.dll"
},
{
"ModuleName": "netutils.dll",
"FileName": "C:\\Windows\\System32\\netutils.dll"
},
{
"ModuleName": "NetworkExplorer.dll",
"FileName": "C:\\Windows\\system32\\NetworkExplorer.dll"
},
{
"ModuleName": "sxs.dll",
"FileName": "C:\\Windows\\SYSTEM32\\sxs.dll"
},
{
"ModuleName": "atlthunk.dll",
"FileName": "C:\\Windows\\SYSTEM32\\atlthunk.dll"
},
{
"ModuleName": "StructuredQuery.dll",
"FileName": "C:\\Windows\\System32\\StructuredQuery.dll"
},
{
"ModuleName": "icu.dll",
"FileName": "C:\\Windows\\System32\\icu.dll"
},
{
"ModuleName": "OneCoreUAPCommonProxyStub.dll",
"FileName": "C:\\Windows\\System32\\OneCoreUAPCommonProxyStub.dll"
},
{
"ModuleName": "Windows.FileExplorer.Common.dll",
"FileName": "C:\\Windows\\System32\\Windows.FileExplorer.Common.dll"
},
{
"ModuleName": "OneCoreCommonProxyStub.dll",
"FileName": "C:\\Windows\\System32\\OneCoreCommonProxyStub.dll"
},
{
"ModuleName": "Windows.System.Launcher.dll",
"FileName": "C:\\Windows\\System32\\Windows.System.Launcher.dll"
},
{
"ModuleName": "windowsudk.shellcommon.dll",
"FileName": "C:\\Windows\\system32\\windowsudk.shellcommon.dll"
},
{
"ModuleName": "Windows.UI.dll",
"FileName": "C:\\Windows\\System32\\Windows.UI.dll"
},
{
"ModuleName": "Windows.UI.Immersive.dll",
"FileName": "C:\\Windows\\System32\\Windows.UI.Immersive.dll"
},
{
"ModuleName": "Windows.StateRepositoryPS.dll",
"FileName": "C:\\Windows\\System32\\Windows.StateRepositoryPS.dll"
},
{
"ModuleName": "Windows.Storage.Search.dll",
"FileName": "C:\\Windows\\system32\\Windows.Storage.Search.dll"
},
{
"ModuleName": "MPR.dll",
"FileName": "C:\\Windows\\System32\\MPR.dll"
},
{
"ModuleName": "vmhgfs.dll",
"FileName": "C:\\Windows\\System32\\vmhgfs.dll"
},
{
"ModuleName": "VERSION.dll",
"FileName": "C:\\Windows\\System32\\VERSION.dll"
},
{
"ModuleName": "VCRUNTIME140.dll",
"FileName": "C:\\Windows\\System32\\VCRUNTIME140.dll"
},
{
"ModuleName": "p9np.dll",
"FileName": "C:\\Windows\\System32\\p9np.dll"
},
{
"ModuleName": "drprov.dll",
"FileName": "C:\\Windows\\System32\\drprov.dll"
},
{
"ModuleName": "ntlanman.dll",
"FileName": "C:\\Windows\\System32\\ntlanman.dll"
},
{
"ModuleName": "davclnt.dll",
"FileName": "C:\\Windows\\System32\\davclnt.dll"
},
{
"ModuleName": "WINSTA.dll",
"FileName": "C:\\Windows\\System32\\WINSTA.dll"
},
{
"ModuleName": "wkscli.dll",
"FileName": "C:\\Windows\\System32\\wkscli.dll"
},
{
"ModuleName": "cscapi.dll",
"FileName": "C:\\Windows\\SYSTEM32\\cscapi.dll"
},
{
"ModuleName": "dlnashext.dll",
"FileName": "C:\\Windows\\System32\\dlnashext.dll"
},
{
"ModuleName": "ntshrui.dll",
"FileName": "C:\\Windows\\SYSTEM32\\ntshrui.dll"
},
{
"ModuleName": "PlayToDevice.dll",
"FileName": "C:\\Windows\\System32\\PlayToDevice.dll"
},
{
"ModuleName": "DevDispItemProvider.dll",
"FileName": "C:\\Windows\\System32\\DevDispItemProvider.dll"
},
{
"ModuleName": "MMDevApi.dll",
"FileName": "C:\\Windows\\System32\\MMDevApi.dll"
},
{
"ModuleName": "DEVOBJ.dll",
"FileName": "C:\\Windows\\System32\\DEVOBJ.dll"
},
{
"ModuleName": "wpdshext.dll",
"FileName": "C:\\Windows\\system32\\wpdshext.dll"
},
{
"ModuleName": "gdiplus.dll",
"FileName": "C:\\Windows\\WinSxS\\amd64_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.26100.8328_none_6ef30b123dc73046\\gdiplus.dll"
},
{
"ModuleName": "PortableDeviceApi.dll",
"FileName": "C:\\Windows\\System32\\PortableDeviceApi.dll"
},
{
"ModuleName": "SETUPAPI.dll",
"FileName": "C:\\Windows\\System32\\SETUPAPI.dll"
},
{
"ModuleName": "WINTRUST.dll",
"FileName": "C:\\Windows\\System32\\WINTRUST.dll"
},
{
"ModuleName": "CRYPT32.dll",
"FileName": "C:\\Windows\\System32\\CRYPT32.dll"
},
{
"ModuleName": "MSASN1.dll",
"FileName": "C:\\Windows\\SYSTEM32\\MSASN1.dll"
},
{
"ModuleName": "EhStorShell.dll",
"FileName": "C:\\Windows\\System32\\EhStorShell.dll"
},
{
"ModuleName": "EhStorAPI.dll",
"FileName": "C:\\Windows\\System32\\EhStorAPI.dll"
},
{
"ModuleName": "WTSAPI32.dll",
"FileName": "C:\\Windows\\System32\\WTSAPI32.dll"
},
{
"ModuleName": "SspiCli.dll",
"FileName": "C:\\Windows\\System32\\SspiCli.dll"
},
{
"ModuleName": "ActXPrxy.dll",
"FileName": "C:\\Windows\\System32\\ActXPrxy.dll"
},
{
"ModuleName": "cscui.dll",
"FileName": "C:\\Windows\\System32\\cscui.dll"
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

@@ -0,0 +1,8 @@
{
"processAbsent": true,
"atUtc": "2026-09-11T16:49:52.8260307Z",
"pid": 6344,
"exitCode": null,
"method": "Native Alt+F4",
"note": "Numeric GUI exit code was not observed"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

@@ -0,0 +1,5 @@
{
"atUtc": "2026-09-11T16:50:02.559946+00:00",
"files": 559,
"completeInventoryUnchanged": true
}
@@ -0,0 +1,561 @@
{
"arcadia-server.exe": "efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665",
"arcadia-studio.exe": "5657bab5c841939b66f901efe6c0ffb2d7cbbe8cc5f111a0ca3de8073d3846ce",
"dependency-notices.json": "f318f87e6a23dcfac16ef7b1cfe51ecb804e98e1ff6a97271180319d5922fc0e",
"documentation-check.json": "bcc89585951fd9e5a1641993c51ca79e00a7a06944a8273d2df413331320e93f",
"libunwind.dll": "f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4",
"LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"package.json": "25f01823dbceed15468bf759eed3f9ffbfd1098427027288bcbb9a3d356b6a4d",
"README.md": "597cfb8da873e019d2658420f18ec059f0185fa9106ff9eafe934dfdd6ed266b",
"SHA256SUMS.txt": "04e4be3f6a081e11ccad8609643031d91fed82cd08e7c7821002ff9b9a04e454",
"START-HERE.txt": "a549295cf57ac73673dc4fa6106463450f982122793cb9c7135ce4fc7087e9ed",
"THIRD-PARTY-NOTICES.txt": "6756989c8fc73706641cd78449c315458425a2eed9a82febc289b9d28ea7f21f",
"deployment/arcadia-server.service": "1e6c6bb4065e25f8fe1d558a4ed0bbd4844782a4377c2482488db1e6f9cab01d",
"deployment/Dockerfile": "72c04aef4ec879955ed3bdf315987553d018ef46e4b8f350f0f6fe380c453eb7",
"deployment/Dockerfile.dockerignore": "6bb7d7496110b11a531cb8cd923864c6610850a8f1c4de8a797f54c7156f29e1",
"docs/api.html": "a06126cb741da57e9c06e83fc4137ccde0de05562673546bc9d405878f51ea07",
"docs/api.rst": "ca7d310138c3b4d429d80a1d03d1ac8d4a9296069e205da573034256d10438a7",
"docs/language.html": "67dcfa3477b48a0b07298ec81741840cc3ccff12c7d58164873d746d41d611c8",
"docs/language.rst": "ac6b1d982c55f246de2f3c844b24b874599a3c20cfbd7ed22efe4561ac622b83",
"docs/linux-packaging.md": "41a1bb1095801df37a1411341c5791d55ea8c365739314d599a60269ac4bc7a0",
"docs/openapi.json": "c6ae512f791a939eaf6ec5e5e78e9468bdee0e028092d00098bd90ad9498d967",
"docs/research-v2-service.md": "4828df5bc679e7c71f49b4b85c9e7dacbec52f46d416fed48af70e08886d4e4e",
"docs/server.md": "4eb24937d424ba8b384e1734e02a6f8e963ae11d2715889c92b14b39ff2e4a48",
"docs/windows-packaging.md": "2c852ff7041713ffbff3c951ac98df647c51fb70b0feba9000f7bfd5bc2703a8",
"examples/coastal-rescue.arcadia": "7e183ef9fd8154d3074303f1956cd0d9871c19e3ffc630d333b0bffbd6e30e17",
"examples/coastal-rescue.json": "242f0b031229a87af5c4ebe5d651defe59c191a6b7a69dc0a77f7e203411f195",
"examples/legacy-v1-coastal-rescue.arcadia": "4dbbbdf8bc7e6cb8e0a81dd678069dae585a9e5187c59bc3665e1fdab3f1a86a",
"examples/legacy-v1-coastal-rescue.oa.json": "fd0e9dedfb7adb922dc0575cc2b820d40344d639f1d8052bd70363aa59de9c24",
"examples/routing-workshop.arcadia": "dc6b75da72884d399132ed9e300fa5a26b73d802bb526c9af986ae9eeb0a646a",
"examples/routing-workshop.json": "8592714f75b271133f21ce017d87896b6cf91ea0e4837f1c2ed453e21be26b14",
"licenses/llvm-mingw-LICENSE.TXT": "8d85c1057d742e597985c7d4e6320b015a9139385cff4cbae06ffc0ebe89afee",
"examples/release1/expected-diagnostics.json": "3700393d76b940cfc076bf52861bd7b1f43370f8eabce3594531bd0bf1fc851e",
"examples/release1/model.json": "ef0ef4006c3e09d5db6e1b621256b3f7d6642f3a7b09cc34607cfbcca830c727",
"examples/release1/model.rs": "15f30f6bde655808fe754665c26d560e36f2a9bad340f346b09137d0d05045f5",
"examples/release1/project.arcadia": "b2674e6bf77cfe0f6f0ba79c81d2e96d92f39c02ca2c6266d80e91723bfb9fda",
"examples/release1/README.md": "113cfb1cf38a98b51bff60442d86a35d636a3d80ef206bece7d53d0aae67f2d5",
"examples/release1/traceability.arcadia": "48a96f543456c9b5a5798fc795594e4119147fe45f11a6f109f141b7f514560f",
"examples/release1/transition-before.json": "2253e6434f741687e22327c37d520ed15c043bc36025498650bc2366bb6a874d",
"examples/release1/transition-request.json": "43b9a22e5f95ad3bc0ebd2478ead0e14406854abc989ae94ded9367b013d812a",
"examples/source-project/oa.arcadia": "5f60642f211b2d352a951092faeeb7503d4fb7f6f7fca99e810347231101d31c",
"examples/source-project/project.arcadia": "787f6b67b179ffd221f7e5faf1a4edd74cfd116aa1e3b5e9ed9f22fbff612d8d",
"examples/source-project/views.arcadia": "e29ad3f406a6a50d2f0ae2ca2a53ee3b0c18222cd4098704a46d4f48b64ea17f",
"examples/text-first/project.arcadia": "f441535c623e0cf20e1875eb2cd33b587ed00e078c37af39cb36d89bb5edc19a",
"examples/text-first/README.md": "4ec8250d5ed556f1d496e8c85137e973e802ecb11df1a36488411e8cdc5a9f9e",
"examples/release1/evidence/repair-check.md": "f4db17bdca4ecbb1bf0caef01b2da5f1f7f798ab3152b648ce6dd8696a6a68e5",
"examples/release1/oa/capabilities.arcadia": "fc8012e5554350b12e1cb80080f8feab80d933c9b33c0f2a7bb500cb7d609936",
"examples/release1/oa/model.arcadia": "f7cf914766ea73ec53b85e32d117ea9a9dba52d3e038246863541ae7069b1a15",
"examples/release1/oa/participants.arcadia": "951764c14179f27c10e315acf2ea37d1fff54c77b8441e23addd239e8c715ce3",
"examples/release1/oa/types.arcadia": "9d0396fb82dd5733edd8d1cf52f968ca84906927c704f9cf0944a7fae215cf49",
"examples/release1/sa/capabilities.arcadia": "b6912fb3ece439912345fa71724acd462e716a1e5a88203a1058a5c3b2c20a4f",
"examples/release1/sa/model.arcadia": "d431509251acb859fbb98733b6d18add952495e10a78703fbe8f31e40bc083c4",
"examples/release1/sa/participants.arcadia": "780d2eb08b217b67b55febb3d34846f727b8ee9018df6c5741748647e36b2ff8",
"examples/release1/sa/types.arcadia": "101fc0fbd99f1101514aa7b6da4f8e535aae0bb94c9e2b9e7e6c151135b28660",
"examples/release1/views/diagram_oa_allocation_view.arcadia": "dfc0eb61e0e2aa5bda45524571fbfa3494f44ce19696f3e15e07438074a07bc7",
"examples/release1/views/diagram_sa_allocation_view.arcadia": "b78b43a26a82efb8fbd5374b09c329fa341f57b29f635d397b9ef8aede71d389",
"examples/release1/views/diagram_sa_capability_view.arcadia": "75e8dc9fb30f25d6f8fd3c6b595593ab4f98958a25798f961e336e0fac557649",
"examples/release1/views/diagram_sa_service_view.arcadia": "b08c84f3ea633e7c78dfdad3272f75415f6256cf3614b6d99bfd4f0269076c9b",
"examples/release1/views/diagram_sa_state_view.arcadia": "5f42f4c605e57b817d8400ed21f2b14bfc4e1592aebe941ff113767504c2b869",
"examples/release1/oa/activities/activity_oa_restore_work.arcadia": "83e73d0a013d5c3e1a4af0d9139ab0cfa362d25a846671fc2dac59181061a9d4",
"examples/release1/oa/behavior/process_oa_assessment_procedure.arcadia": "172c32c044ef4b5bc58a1f4635cc81f48dabb4014479b47dce7b25fedf2dbd0d",
"examples/release1/oa/behavior/process_oa_field_procedure.arcadia": "d2552dc5383e2e91cb302a790364e197f663c2edc013a2ab1978789825c9c324",
"examples/release1/oa/behavior/process_oa_response.arcadia": "cf86f46fa5c5d70592ef43f1bc1cb4d968efd8add384ba88036bef6b88aa4abc",
"examples/release1/oa/behavior/scenario_oa_conversation.arcadia": "b25be524e98a35ebac5e4481b7609c027b32baf9605e8097f807560f94a77ca6",
"examples/release1/oa/behavior/scenario_oa_full_scenario.arcadia": "00a1edf2c9707a0eb62ac070c2d02467874f2c9c1f273cc6ddb53d6d65999a1c",
"examples/release1/oa/behavior/state_machine_oa_monitor.arcadia": "447c9ad1359f4a31ecf975ad07c0b08d8e7e03191fb0858e2fc56f377b223cd5",
"examples/release1/sa/behavior/process_sa_assessment_procedure.arcadia": "73928ced61c06cbc08728d7956676a50fd4c05aa5b7f1ff4f29ce27a0b0f2088",
"examples/release1/sa/behavior/process_sa_field_procedure.arcadia": "886d462af83110cbfa55dd232a667ea1446761234471357cbb878794e98e8768",
"examples/release1/sa/behavior/process_sa_response.arcadia": "041785fc22842423822431bd5e6e8d16094ebd0716965e7c765fb8c1d7549e8a",
"examples/release1/sa/behavior/scenario_sa_conversation.arcadia": "97276f5757ee9aa12a0dbd9d3ccd58174b3091162bb8bcce357cec20a45f5d85",
"examples/release1/sa/behavior/scenario_sa_full_scenario.arcadia": "e12fc406b99d60a2f7768aaa0b25ba560e8605f0b8e37f3a7cdd3b8443562b74",
"examples/release1/sa/behavior/state_machine_sa_monitor.arcadia": "05ce29af99424c491c47fe2450dc6f5f8ce995511c01ec7e17bb5855be3c9736",
"examples/release1/sa/functions/function_sa_audit_thresholds.arcadia": "e5a04325d52183956dca814dd90f4e56c96c6b7db0f4f202f203ecb49c3e0f4f",
"examples/release1/sa/functions/function_sa_restore_work.arcadia": "fddeb67308051325041fee641fe758ddf43345b7c47b66d433616ad07fdccdd6",
"examples/source-project/sa/assurance.arcadia": "ab76044836e4dcd42a82d316846ec87da2108939aa2037640c5bca1d2ecdee0f",
"examples/source-project/sa/participants.arcadia": "1abad579812e77877b45a3d8e3c3e9da734be2d04a0254cc730a5257ebd2dc88",
"examples/source-project/sa/reporting.arcadia": "f0b7443f728912ca163de39b6055876b533a77feaa3219b2d40a2dd65712e058",
"licenses/llvm-libunwind/llvm-ea7d852a70e8-libunwind-LICENSE.TXT": "b5efebcaca80879234098e52d1725e6d9eb8fb96a19fce625d39184b705f7b6d",
"licenses/rust/COPYING.RUNTIME": "28e85c5aa4af9b4f1dfe6b4817aa3eefb3eaaee7fd735045016f29ccf50276a1",
"licenses/rust/COPYING3": "8ceb4b9ee5adedde47b31e975c1d90c73ad27b6b165a1dcd80c7c545eb65b903",
"licenses/rust/COPYRIGHT-library.html": "68129500b616d5838629e68f55ff3aed5e096dacf60ce9eb41bbe599a563afa6",
"licenses/rust/COPYRIGHT.html": "5b0c93fc4e6d4b072eaa521b1762d1e746f4c368f65e81a0e5308e2772dac85e",
"licenses/dependencies/arrayref-0.3.9/LICENSE": "1bc7e6f475b3ec99b7e2643411950ae2368c250dd4c5c325f80f9811362a94a1",
"licenses/dependencies/arrayvec-0.7.8/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/arrayvec-0.7.8/LICENSE-MIT": "4da95ec4ecb65b738d470b7d762894ad9c97da93e6cbfb18b570fc2c96f4b871",
"licenses/dependencies/ash-0.38.0+1.3.281/LICENSE-APACHE": "0e8a410375e1ee5c75c6198b08b534fec6e5edef766cf971bab4a404542636ab",
"licenses/dependencies/ash-0.38.0+1.3.281/LICENSE-MIT": "c733ccf8ab25df175a63d9d844677b98e3a5ab8f8de1c1616087e6868a7f948e",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/atomic-waker-1.1.2/LICENSE-THIRD-PARTY": "6226d0632e2e1a80c23597e964da9812ae193c535fe058154afb034e94167aa5",
"licenses/dependencies/autocfg-1.5.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/autocfg-1.5.1/LICENSE-MIT": "27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac",
"licenses/dependencies/axum-0.8.9/LICENSE": "6a13bc24a100a6812f053879ec51b126b103af7cda6dbf48c4188722da44da9f",
"licenses/dependencies/axum-core-0.5.6/LICENSE": "008c87afcd2e626eaf564093250bed06dd7efb5732113264bba3dda8f1c556a1",
"licenses/dependencies/base64-0.22.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/base64-0.22.1/LICENSE-MIT": "0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7",
"licenses/dependencies/bit-set-0.8.0/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/bit-set-0.8.0/LICENSE-MIT": "f51ac2c59a222f7476ce507ca879960e2b64ea64bb2786eefdbeb7b0b538d1b7",
"licenses/dependencies/bit-vec-0.8.0/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/bit-vec-0.8.0/LICENSE-MIT": "f51ac2c59a222f7476ce507ca879960e2b64ea64bb2786eefdbeb7b0b538d1b7",
"licenses/dependencies/bitflags-2.13.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/bitflags-2.13.1/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-APACHE": "e3ba223bb1423f0aad8c3dfce0fe3148db48926d41e6fbc3afbbf5ff9e1c89cb",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-MIT": "9df9ba60a11af705f2e451b53762686e615d86f76b169cf075c3237730dbd7e2",
"licenses/dependencies/bytemuck-1.25.2/LICENSE-ZLIB": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-APACHE": "e3ba223bb1423f0aad8c3dfce0fe3148db48926d41e6fbc3afbbf5ff9e1c89cb",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-MIT": "9df9ba60a11af705f2e451b53762686e615d86f76b169cf075c3237730dbd7e2",
"licenses/dependencies/bytemuck_derive-1.12.0/LICENSE-ZLIB": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/bytes-1.12.1/LICENSE": "45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42",
"licenses/dependencies/cc-1.4.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cc-1.4.5/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/cfg-if-1.0.4/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cfg-if-1.0.4/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/cfg_aliases-0.2.2/LICENSE": "31b94860253d8ec7b4529f51901044d3b459d6292d996504a36b1bae3a36a812",
"licenses/dependencies/chacha20-0.10.2/LICENSE-APACHE": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
"licenses/dependencies/chacha20-0.10.2/LICENSE-MIT": "b8c6939380a400f53e11923d50fcc4dd2fa1ba8339fd9d04cda38a0251b6c9b0",
"licenses/dependencies/codespan-reporting-0.12.0/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/core_maths-0.1.1/LICENSE": "9ebf8c4cc0b735ca13a766451f7b8097db3185975ceb2ba94b5abf439156a91f",
"licenses/dependencies/cosmic-text-0.15.0/LICENSE-APACHE": "000b4962e6b27176a0ff89cce4be555b16472cafb5671eb2804a8fdac6854793",
"licenses/dependencies/cosmic-text-0.15.0/LICENSE-MIT": "95557bafe728379e206f3b6d4aceeaa054d271c71d722411a6222e2dec01138c",
"licenses/dependencies/cpufeatures-0.3.1/LICENSE-APACHE": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
"licenses/dependencies/cpufeatures-0.3.1/LICENSE-MIT": "73b9dc2e79c7308998dd30296e073aefaefb944a68fb89aa412c23c0edcabcaa",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/cryoglyph-0.1.0/LICENSE-ZLIB": "b3ec01ad0869c5c50937bc68780cd0bb44e235ad858dfa54a7a381dced9b115a",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-APACHE": "b59affd015e517ed998dd735757f9a3693643cd389609947ed54074234a10784",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-MIT": "c138726a726ac37bae09d0f8a48e74e8e3aa8a8952fcd10fae0fb224cc1c05f1",
"licenses/dependencies/cursor-icon-1.2.0/LICENSE-ZLIB": "01e533bd94e8f1c32b2c2531e2c398de7d35d7804add3d574b4e1fe581d53537",
"licenses/dependencies/displaydoc-0.2.7/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/displaydoc-0.2.7/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/document-features-0.2.12/LICENSE-APACHE": "074e6e32c86a4c0ef8b3ed25b721ca23aca83df277cd88106ef7177c354615ff",
"licenses/dependencies/document-features-0.2.12/LICENSE-MIT": "aa893340d14b9844625be6a50ac644169a01b52f0211cbf81b09e1874c8cd81d",
"licenses/dependencies/dpi-0.1.2/LICENSE": "6dc0e068dcf3a5bc8e054205b85b7720e1d49265bbc64bf515d2cf79197df69a",
"licenses/dependencies/dpi-0.1.2/LICENSE-LIBM-MIT": "9eff396a99bafd208e7126602420d6864f6066c08b84485a5b032320a9c01997",
"licenses/dependencies/equivalent-1.0.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/equivalent-1.0.2/LICENSE-MIT": "7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349",
"licenses/dependencies/error-code-3.4.0/LICENSE": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/etagere-0.2.15/LICENSE-APACHE": "2d56a37f3d1e461f6b1539ab94e0e6bcc55443e376098aee85ac3b2890860290",
"licenses/dependencies/etagere-0.2.15/LICENSE-MIT": "9cfc9c9a4608501b5da3746948d2be2dd709ad51f6bcb0c1c685760ee3dde31f",
"licenses/dependencies/euclid-0.22.14/COPYRIGHT": "ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a",
"licenses/dependencies/euclid-0.22.14/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/euclid-0.22.14/LICENSE-MIT": "62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3",
"licenses/dependencies/fastrand-2.5.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/fastrand-2.5.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/find-msvc-tools-0.1.12/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/find-msvc-tools-0.1.12/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/float_next_after-1.0.0/LICENSE": "0604d5817110dacc5c7d9b7de6b58b962794603d4823c357157bd5dec4198bc5",
"licenses/dependencies/foldhash-0.1.5/LICENSE": "b1181a40b2a7b25cf66fd01481713bc1005df082c53ef73e851e55071b102744",
"licenses/dependencies/foldhash-0.2.0/LICENSE": "b1181a40b2a7b25cf66fd01481713bc1005df082c53ef73e851e55071b102744",
"licenses/dependencies/font-types-0.10.1/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/font-types-0.10.1/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/font-types-0.12.4/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/font-types-0.12.4/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/fontdb-0.23.0/LICENSE": "59a1fdac3bd550043599bd159fd70f09a1108c2b09e3751d39b11e1ff8e51f00",
"licenses/dependencies/form_urlencoded-1.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/form_urlencoded-1.2.2/LICENSE-MIT": "20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e",
"licenses/dependencies/futures-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-channel-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-channel-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-core-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-core-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-executor-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-executor-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-io-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-io-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-macro-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-macro-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-sink-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-sink-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-task-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-task-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/futures-util-0.3.34/LICENSE-APACHE": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
"licenses/dependencies/futures-util-0.3.34/LICENSE-MIT": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
"licenses/dependencies/getrandom-0.2.17/LICENSE-APACHE": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
"licenses/dependencies/getrandom-0.2.17/LICENSE-MIT": "42fa16951ce7f24b5a467a40e5b449a1d41e662f97ca779864f053f39e097737",
"licenses/dependencies/getrandom-0.4.3/LICENSE-APACHE": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
"licenses/dependencies/getrandom-0.4.3/LICENSE-MIT": "523a42c25d245dde9c015f882cec7f4555aad883382a6cf19b4b7d9b2cd5419b",
"licenses/dependencies/glam-0.25.0/LICENSE-APACHE": "be33ddb87a30fd321ab100e2d922cba512e50ec7a63d8e62e5bfc0798dd4b585",
"licenses/dependencies/glam-0.25.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/glow-0.16.0/LICENSE-APACHE": "b8601fc79bdf8d8088f0938bea861ffc63ed0eebbedf25f44ab2cf2e85bd7edc",
"licenses/dependencies/glow-0.16.0/LICENSE-MIT": "cdbd06e25b8c9c5d6019949d2de8123f56d29cee4166396423d2ba8c81700845",
"licenses/dependencies/glow-0.16.0/LICENSE-ZLIB": "636f644f1e149eb62961657c0e34953681eff64435653912e7bd19992666faa5",
"licenses/dependencies/glutin_wgl_sys-0.6.1/LICENSE": "a4445427440043e8ce6fadf7a43fb906cb0d7f6c573a560a9f142cf9f9bf8ff4",
"licenses/dependencies/gpu-allocator-0.27.0/LICENSE-APACHE": "0178e21322b0e88aa3aeb3146f6a9611bc1f8df6d98bdfb34be28b9dd56a8107",
"licenses/dependencies/gpu-allocator-0.27.0/LICENSE-MIT": "ad41be6cc6538b29b9346648f41432b5e460bad6be073b5eeaa41320ea2921dc",
"licenses/dependencies/guillotiere-0.6.2/LICENSE": "7e98bed7f100747aaae7d82ab94fbe6b76fd6b84b09a3aaa413bff8196d0fbb1",
"licenses/dependencies/half-2.7.1/LICENSE-APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/half-2.7.1/LICENSE-MIT": "508a77d2e7b51d98adeed32648ad124b7b30241a8e70b2e72c99f92d8e5874d1",
"licenses/dependencies/harfrust-0.3.2/LICENSE": "7d43d2ef1ce976c7bfb423c696ad9938ccfc31e9ec5be752265e43fe9d29f697",
"licenses/dependencies/hashbrown-0.15.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.15.5/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/hashbrown-0.16.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.16.1/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/hashbrown-0.17.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hashbrown-0.17.1/LICENSE-MIT": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
"licenses/dependencies/http-1.5.0/LICENSE-APACHE": "8bb1b50b0e5c9399ae33bd35fab2769010fa6c14e8860c729a52295d84896b7a",
"licenses/dependencies/http-1.5.0/LICENSE-MIT": "dc91f8200e4b2a1f9261035d4c18c33c246911a6c0f7b543d75347e61b249cff",
"licenses/dependencies/http-body-1.1.0/LICENSE": "248378d0a3383c173fb925f17141b88e71580b3ba17ddc6ac3d2a344683232ab",
"licenses/dependencies/http-body-util-0.1.5/LICENSE": "248378d0a3383c173fb925f17141b88e71580b3ba17ddc6ac3d2a344683232ab",
"licenses/dependencies/httparse-1.10.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/httparse-1.10.1/LICENSE-MIT": "391a5396cec6230bfabd4ef4eb2350eb895bc5efce377a2218f5702ed020d3e3",
"licenses/dependencies/httpdate-1.0.3/LICENSE-APACHE": "4d10fe5f3aa176b05b229a248866bad70b834c173f1252a814ff4748d8a13837",
"licenses/dependencies/httpdate-1.0.3/LICENSE-MIT": "934887691e05d69d7c86ad3f2c360980fa30c15b035e351f3c9865e99da4debc",
"licenses/dependencies/hyper-1.11.1/LICENSE": "2d01890414494742ba4a509fcec8efa40f6d8be22cbd72be7cff08d6fda4ec89",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-ISC": "7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4",
"licenses/dependencies/hyper-rustls-0.27.9/LICENSE-MIT": "709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c",
"licenses/dependencies/hyper-util-0.1.20/LICENSE": "9e0a97848ea543aef745c98e84fde696a9a3e0735538f6daefdd3cb1942effc1",
"licenses/dependencies/iced-0.14.0/LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/icu_collections-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_locale_core-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_normalizer-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_normalizer_data-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_properties-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_properties_data-2.3.0/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/icu_provider-2.3.1/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/idna-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/idna-1.1.0/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/idna_adapter-1.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/idna_adapter-1.2.2/LICENSE-MIT": "8b43ce8accd61e9d370b5ca9e9c4f953279b5c239926c62315b40e24df51b726",
"licenses/dependencies/indexmap-2.14.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/indexmap-2.14.1/LICENSE-MIT": "ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055",
"licenses/dependencies/ipnet-2.12.1/LICENSE-APACHE": "87d9feb9238c6bd8e0024fc4733b06cff036f89f36d93b7df1c8a0549bbb7a5b",
"licenses/dependencies/ipnet-2.12.1/LICENSE-MIT": "47dc9ff29128ddfb4d6a0435383c9f89120bc374dbcc1dd00b933a0b28aa7865",
"licenses/dependencies/itoa-1.0.18/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/itoa-1.0.18/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/jobserver-0.1.35/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/jobserver-0.1.35/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/khronos-egl-6.0.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/khronos-egl-6.0.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/kurbo-0.10.4/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/kurbo-0.10.4/LICENSE-MIT": "23c23145f6eac25c28cdcc03d38506a5712a9a8cffb5bd5301457f6173ea696e",
"licenses/dependencies/libc-0.2.189/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/libc-0.2.189/LICENSE-MIT": "123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e",
"licenses/dependencies/libloading-0.8.9/LICENSE": "b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f",
"licenses/dependencies/libm-0.2.16/LICENSE.txt": "3823dda7cf046602f4b4e77ec8e227863dc4736037cc85bb33d9f19febe16bb7",
"licenses/dependencies/lilt-0.8.2/LICENSE": "120b2f21f9b9f98ef4159de09f9a55a3afb6733dd1c0b1d9eeec7f136465b2cd",
"licenses/dependencies/linebender_resource_handle-0.1.1/LICENSE-APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/linebender_resource_handle-0.1.1/LICENSE-MIT": "508a77d2e7b51d98adeed32648ad124b7b30241a8e70b2e72c99f92d8e5874d1",
"licenses/dependencies/litemap-0.8.3/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/litrs-1.0.0/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/litrs-1.0.0/LICENSE-MIT": "7dc1552e88f49132cb358b1b962fc5e79fa42d70bcbb88c526d33e45b8e98036",
"licenses/dependencies/lock_api-0.4.14/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/lock_api-0.4.14/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/log-0.4.34/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/log-0.4.34/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/lru-0.16.4/LICENSE": "061dc50af2cd9340703daf61978af3200cf681b12ea67a323c33ba109a23a45e",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-MIT": "1466d9b4f3a59bb8997fc8d5fa977ce3f6a24bb2358793c09bfdf007039f6486",
"licenses/dependencies/lru-slab-0.1.2/LICENSE-ZLIB": "09785877275ffada6c371b652a30e95c26b435126fc0fc62f1bc2d72171f80a4",
"licenses/dependencies/matchit-0.8.4/LICENSE": "de701d0618d694feb1af90f02181a1763d9b0bdeb70a3a592781e529077dba65",
"licenses/dependencies/matchit-0.8.4/LICENSE.httprouter": "162ce11ad71338d0a0c6ebaf5c48af72c6ae237b468859d3656fe2d9ed3f3a85",
"licenses/dependencies/memchr-2.8.3/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/memchr-2.8.3/LICENSE-MIT": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
"licenses/dependencies/memchr-2.8.3/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/memmap2-0.9.11/LICENSE-APACHE": "04ea4849dba9dcae07113850c6f1b1a69052c625210639914eee352023f750ad",
"licenses/dependencies/memmap2-0.9.11/LICENSE-MIT": "0d25d03b5ab49576178ad0cae7a2648d12c17ad0452fe49c07e55e4b59aa5257",
"licenses/dependencies/mime-0.3.17/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/mime-0.3.17/LICENSE-MIT": "df9cfd06d8a44d9a671eadd39ffd97f166481da015a30f45dfd27886209c5922",
"licenses/dependencies/mio-1.2.3/LICENSE": "07919255c7e04793d8ea760d6c2ce32d19f9ff02bdbdde3ce90b1e1880929a9b",
"licenses/dependencies/naga-27.0.3/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/naga-27.0.3/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/num-traits-0.2.19/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/num-traits-0.2.19/LICENSE-MIT": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
"licenses/dependencies/oa-core-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/oa-desktop-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/oa-server-0.2.0/workspace-LICENSE": "51009f2cb07e5d19645858b2fbc037a672a25f8cbf7999522942b86807ecf365",
"licenses/dependencies/once_cell-1.21.4/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/once_cell-1.21.4/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/ordered-float-5.5.0/LICENSE-MIT": "f7715d38a3fa1b4ac97c5729740752505a39cb92ee83ab5b102aeb5eaa7cdea4",
"licenses/dependencies/parking_lot-0.12.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/parking_lot-0.12.5/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/parking_lot_core-0.9.12/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/parking_lot_core-0.9.12/LICENSE-MIT": "c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5",
"licenses/dependencies/percent-encoding-2.3.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/percent-encoding-2.3.2/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/pin-project-lite-0.2.17/LICENSE-APACHE": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/pin-project-lite-0.2.17/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/pkg-config-0.3.34/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/pkg-config-0.3.34/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/potential_utf-0.1.6/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/presser-0.3.1/LICENSE-APACHE": "8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90",
"licenses/dependencies/presser-0.3.1/LICENSE-MIT": "090a294a492ab2f41388252312a65cf2f0e423330b721a68c6665ac64766753b",
"licenses/dependencies/proc-macro2-1.0.107/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/proc-macro2-1.0.107/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/quinn-0.11.11/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-0.11.11/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quinn-proto-0.11.17/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-proto-0.11.17/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quinn-udp-0.5.15/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/quinn-udp-0.5.15/LICENSE-MIT": "4b2d0aca6789fa39e03d6738e869ea0988cceba210ca34ebb59c15c463e93a04",
"licenses/dependencies/quote-1.0.47/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/quote-1.0.47/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/rand-0.10.2/COPYRIGHT": "90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5",
"licenses/dependencies/rand-0.10.2/LICENSE-APACHE": "35242e7a83f69875e6edeff02291e688c97caafe2f8902e4e19b49d3e78b4cab",
"licenses/dependencies/rand-0.10.2/LICENSE-MIT": "209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b",
"licenses/dependencies/rand_core-0.10.1/COPYRIGHT": "92b81db30f7ab6d693e0af5661a40d273ca1947e891123ed823924192c10cbc7",
"licenses/dependencies/rand_core-0.10.1/LICENSE-APACHE": "6df43f6f4b5d4587f3d8d71e45532c688fd168afa5fe89d571cb32fa09c4ef51",
"licenses/dependencies/rand_core-0.10.1/LICENSE-MIT": "8b6e9feec03e7c9a5facb26855cecd31662bf989b636bcfe79521bdf8ac863f0",
"licenses/dependencies/rand_pcg-0.10.2/COPYRIGHT": "90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5",
"licenses/dependencies/rand_pcg-0.10.2/LICENSE-APACHE": "6df43f6f4b5d4587f3d8d71e45532c688fd168afa5fe89d571cb32fa09c4ef51",
"licenses/dependencies/rand_pcg-0.10.2/LICENSE-MIT": "2234e3cefee876aeb686ad89e978bdb07bf118a1186ab1cf161bcdf69d4b4f57",
"licenses/dependencies/range-alloc-0.1.5/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/range-alloc-0.1.5/LICENSE.MIT": "ba00052102ed87948bb8822d6e1c496260c83042887b22bb5caad922ec025a60",
"licenses/dependencies/rangemap-1.8.0/LICENSE-APACHE": "1c7745cc26c7294bc9dbc883bcd50700b99a8c0f4859bfce84ec555098ce1ab5",
"licenses/dependencies/rangemap-1.8.0/LICENSE-MIT": "29a4c3823ee29ee5a97c145574a1bac20629fd5e6708be1df0d25bab563e093c",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-APACHE.md": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-MIT.md": "9c5a80639a57c1c945570e7ebbca0706305849ce3c098021325cca9db2f7acc4",
"licenses/dependencies/raw-window-handle-0.6.2/LICENSE-ZLIB.md": "ae895c8576e682f310fb70d93d9f99b1dd82872094c54a8f6cdfe2ca5c2d6ecb",
"licenses/dependencies/read-fonts-0.35.0/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/read-fonts-0.35.0/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/read-fonts-0.41.0/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/read-fonts-0.41.0/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/renderdoc-sys-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/renderdoc-sys-1.1.0/LICENSE-MIT": "24b2f2eff5a7622e87162823e260f00c6dfbce0e26d585d3d28c785f1edc80ed",
"licenses/dependencies/reqwest-0.12.28/LICENSE-APACHE": "751963a8b88c0e3a9f27e98933079fbcf09b9998b2c13ac49c2e4d58444520d6",
"licenses/dependencies/reqwest-0.12.28/LICENSE-MIT": "47d4e1803702728e03d30f8a848ae2249ba274bbd9f8443e803f7924d83cd371",
"licenses/dependencies/rfd-0.15.4/LICENSE": "65fc947f4bac882a2cd104ef73c246b1b037059df9f2b3a58b7f77f0b9e56071",
"licenses/dependencies/ring-0.17.14/LICENSE": "b3d734001a94efff3579978d953391aa7115f877657d25eb54037a43875d078a",
"licenses/dependencies/ring-0.17.14/LICENSE-BoringSSL": "005fc765ddc5115da796cca915baa9557abae13ff35e0a47c47affc56f6c414d",
"licenses/dependencies/ring-0.17.14/LICENSE-other-bits": "f025ccfb7dfb6bdfedc75ca0f67acc69e6fb4998143d834f7c2f38a29989680f",
"licenses/dependencies/rustc-hash-1.1.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/rustc-hash-1.1.0/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/rustc-hash-2.1.3/LICENSE-APACHE": "95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc",
"licenses/dependencies/rustc-hash-2.1.3/LICENSE-MIT": "30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652",
"licenses/dependencies/rustls-0.23.43/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/rustls-0.23.43/LICENSE-ISC": "7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4",
"licenses/dependencies/rustls-0.23.43/LICENSE-MIT": "709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c",
"licenses/dependencies/rustls-pki-types-1.15.1/LICENSE-APACHE": "45fd05c4865e7c350b98ad7ac50e1b15462d49af4a91e9b0c9dd933dc9a69742",
"licenses/dependencies/rustls-pki-types-1.15.1/LICENSE-MIT": "9117d922e667125508dde62b02c1f57ed22f5ad21eb536aa2e2d99e1c796e639",
"licenses/dependencies/rustls-webpki-0.103.15/LICENSE": "5b698ca13897be3afdb7174256fa1574f8c6892b8bea1a66dd6469d3fe27885a",
"licenses/dependencies/ryu-1.0.23/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/ryu-1.0.23/LICENSE-BOOST": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/same-file-1.0.6/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/same-file-1.0.6/LICENSE-MIT": "cb3c929a05e6cbc9de9ab06a4c57eeb60ca8c724bef6c138c87d3a577e27aa14",
"licenses/dependencies/same-file-1.0.6/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/scopeguard-1.2.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/scopeguard-1.2.0/LICENSE-MIT": "fb77f0a9c53e473abe5103c8632ef9f0f2874d4fb3f17cb2d8c661aab9cee9d7",
"licenses/dependencies/self_cell-1.3.0/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/self_cell-1.3.0/LICENSE-GPLv2": "f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505",
"licenses/dependencies/serde-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_core-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_core-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_derive-1.0.229/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_derive-1.0.229/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_json-1.0.151/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_json-1.0.151/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_path_to_error-0.1.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_path_to_error-0.1.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/serde_urlencoded-0.7.1/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/serde_urlencoded-0.7.1/LICENSE-MIT": "b9eb266294324f672cbe945fe8f2e32f85024f0d61a1a7d14382cdde0ac44769",
"licenses/dependencies/sha1_smol-1.0.1/LICENSE": "282a21b0710441c364025461a447362daf18f5798a7b72ae2f801a2aa536da51",
"licenses/dependencies/shlex-2.0.1/LICENSE-APACHE": "553fffcd9b1cb158bc3e9edc35da85ca5c3b3d7d2e61c883ebcfa8a65814b583",
"licenses/dependencies/shlex-2.0.1/LICENSE-MIT": "4455bf75a91154108304cb283e0fea9948c14f13e20d60887cf2552449dea3b1",
"licenses/dependencies/skrifa-0.37.0/LICENSE-APACHE": "a14f7d685a79c0f4fb64aee305527a6d5fa55f2401f4e6d688d7b1301868e6c0",
"licenses/dependencies/skrifa-0.37.0/LICENSE-MIT": "8a62fa27ffdccc3df19dce90f8bb3d572e27aecffc1a383d0c2601834dcec434",
"licenses/dependencies/skrifa-0.44.0/LICENSE-APACHE": "eba684204073ed715c4abb48129acdfd2bff8ae48339e6a7da3b341d3027b7f0",
"licenses/dependencies/skrifa-0.44.0/LICENSE-MIT": "7b4c9a3946dfcea7967582760e963e27799e225dcf20565c8ef55324bb017427",
"licenses/dependencies/slab-0.4.12/LICENSE": "8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18",
"licenses/dependencies/slotmap-1.1.1/LICENSE": "6cec81441b2ab2b5090954c1fb5d0bcca81b86487b5849061fa8952d20ef67d4",
"licenses/dependencies/smallvec-1.16.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/smallvec-1.16.0/LICENSE-MIT": "0b28172679e0009b655da42797c03fd163a3379d5cfa67ba1f1655e974a2a1a9",
"licenses/dependencies/smol_str-0.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/smol_str-0.2.2/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/socket2-0.6.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/socket2-0.6.5/LICENSE-MIT": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
"licenses/dependencies/softbuffer-0.4.8/LICENSE-APACHE": "a4445427440043e8ce6fadf7a43fb906cb0d7f6c573a560a9f142cf9f9bf8ff4",
"licenses/dependencies/softbuffer-0.4.8/LICENSE-MIT": "0463bfa47d6d763d8c824333efb0e6d6df3946c13c3b077c78ed9f23ca50d0f2",
"licenses/dependencies/stable_deref_trait-1.2.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/stable_deref_trait-1.2.1/LICENSE-MIT": "5e05b024f653a5ce199e77cbbbd42fb5553562ec714b819421ed0c3e552a75d7",
"licenses/dependencies/static_assertions-1.1.0/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/static_assertions-1.1.0/LICENSE-MIT": "ea084a2373ebc1f0902c09266e7bf25a05ab3814c1805bb017ffa7308f90c061",
"licenses/dependencies/strict-num-0.1.1/LICENSE": "3085885678bb161f6c472bbd331f66a2550b555eb76128f7f8247779128199c0",
"licenses/dependencies/subtle-2.6.1/LICENSE": "d1fc1bc0d155df60b2e7705b6b2ae02a05c96f948e1cec6e2fb86360b09f346b",
"licenses/dependencies/swash-0.2.10/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/swash-0.2.10/LICENSE-MIT": "122dadfc2eb4de0f4bafcd9eb4e7502cfe338a7965ebd1d18708cc5050f43f76",
"licenses/dependencies/syn-2.0.119/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/syn-2.0.119/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/syn-3.0.5/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/syn-3.0.5/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/sync_wrapper-1.0.2/LICENSE": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"licenses/dependencies/synstructure-0.13.2/LICENSE": "219920e865eee70b7dcfc948a86b099e7f4fe2de01bcca2ca9a20c0a033f2b59",
"licenses/dependencies/sys-locale-0.3.2/LICENSE-APACHE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/sys-locale-0.3.2/LICENSE-MIT": "5cc390ab5e5e6507f467368cbab1297552d64bfd863f4b496c7928508bcfefd8",
"licenses/dependencies/tempfile-3.27.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/tempfile-3.27.0/LICENSE-MIT": "8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36",
"licenses/dependencies/termcolor-1.4.1/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/termcolor-1.4.1/LICENSE-MIT": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
"licenses/dependencies/termcolor-1.4.1/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/thiserror-1.0.69/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-1.0.69/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-2.0.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-2.0.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-impl-1.0.69/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-impl-1.0.69/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/thiserror-impl-2.0.20/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/thiserror-impl-2.0.20/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/tiny-skia-0.11.4/LICENSE": "6d41e05f1d54fe726997cb0334ec539f1dff50600b1d5d90462ec2b392770ced",
"licenses/dependencies/tiny-skia-path-0.11.4/LICENSE": "6d41e05f1d54fe726997cb0334ec539f1dff50600b1d5d90462ec2b392770ced",
"licenses/dependencies/tinystr-0.8.4/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-APACHE.md": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-MIT.md": "fd80a26fbb3f644af1fa994134446702932968519797227e07a1368dea80f0bc",
"licenses/dependencies/tinyvec-1.13.2/LICENSE-ZLIB.md": "84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-APACHE.md": "4f44572785f35152c1fd2eadf565b7e079c0f300b4324f0af653419f9d76b735",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-MIT.md": "1dd8eca0f83669e75fa119e34fb9e1be9d16e3e9b6368962b8019db6e8ae5f7b",
"licenses/dependencies/tinyvec_macros-0.1.1/LICENSE-ZLIB.md": "41ace205715d9f19a3214218cc1c01d57c533e02cd0fef7c8e51a49a7fce5ac5",
"licenses/dependencies/tokio-1.53.1/LICENSE": "253cd04c6714889df2d32f3f64d669179a1c95c76ac43c40882c52eb06bc3552",
"licenses/dependencies/tokio-macros-2.7.2/LICENSE": "0b83dc40cba89b9922bb84b0a9c7d2768ce37c1d7e138b7424fd4549915778c9",
"licenses/dependencies/tokio-rustls-0.26.5/LICENSE-APACHE": "cc117d90b498b32b11a886f279b359da16a73c3b01efbb2f5cc004b20262334e",
"licenses/dependencies/tokio-rustls-0.26.5/LICENSE-MIT": "e20fa2b8e0a2565f24a792b94b4bf4b6c2b9d36f781d8a9516e218a036e6677a",
"licenses/dependencies/tower-0.5.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tower-http-0.6.11/LICENSE": "5049cf464977eff4b4fcfa7988d84e74116956a3eb9d5f1d451b3f828f945233",
"licenses/dependencies/tower-layer-0.3.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tower-service-0.3.3/LICENSE": "4249c8e6c5ebb85f97c77e6457c6fafc1066406eb8f1ef61e796fbdc5ff18482",
"licenses/dependencies/tracing-0.1.44/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/tracing-attributes-0.1.31/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/tracing-core-0.1.36/LICENSE": "898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1",
"licenses/dependencies/try-lock-0.2.5/LICENSE": "c816a0749cdc6bf062a5111c159723de51b2bfac66a1dac2655abd9e6b1583eb",
"licenses/dependencies/ttf-parser-0.25.1/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/ttf-parser-0.25.1/LICENSE-MIT": "f3c9fe731c701ed77fd5fbaac573872af04dc5869385eb9bd5e3c73c42713814",
"licenses/dependencies/unicode-bidi-0.3.18/COPYRIGHT": "edb20b474f6cbd4f4db066b54a9e0f687d0009d309412a63431189b59b8e2a07",
"licenses/dependencies/unicode-bidi-0.3.18/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-bidi-0.3.18/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-APACHE": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/unicode-ident-1.0.24/LICENSE-UNICODE": "f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1",
"licenses/dependencies/unicode-linebreak-0.1.5/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
"licenses/dependencies/unicode-script-0.5.8/LICENSE-APACHE": "7cbb56d1b5d83d735056b363ab20958524120afafc4ad8206e6be98cdec5d737",
"licenses/dependencies/unicode-script-0.5.8/LICENSE-MIT": "7ad3ea8ca3caf894db98c3f31d5d4949173ffa93c883ef19a9e529ad48960f8c",
"licenses/dependencies/unicode-segmentation-1.13.3/COPYRIGHT": "23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d",
"licenses/dependencies/unicode-segmentation-1.13.3/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-segmentation-1.13.3/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/unicode-width-0.2.2/COPYRIGHT": "23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d",
"licenses/dependencies/unicode-width-0.2.2/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/unicode-width-0.2.2/LICENSE-MIT": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
"licenses/dependencies/untrusted-0.9.0/LICENSE.txt": "7abd9b6960dcf7d4d0a48606a5b71bfe37d472db68d70637f3a58a56785f1621",
"licenses/dependencies/url-2.5.8/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/url-2.5.8/LICENSE-MIT": "b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5",
"licenses/dependencies/utf8_iter-1.0.4/COPYRIGHT": "c30152c94a6d75e021adbc52b3a52470366a46edb917e17deae3259251af244c",
"licenses/dependencies/utf8_iter-1.0.4/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/utf8_iter-1.0.4/LICENSE-MIT": "3fa4ca83dcc9237839b1bdeb2e6d16bdfb5ec0c5ce42b24694d8bbf0dcbef72c",
"licenses/dependencies/uuid-1.26.0/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/uuid-1.26.0/LICENSE-MIT": "436bc5a105d8e57dcd8778730f3754f7bf39c14d2f530e4cde4bd2d17a83ec3d",
"licenses/dependencies/version_check-0.9.5/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/version_check-0.9.5/LICENSE-MIT": "b7e650f3fce5c53249d1cdc608b54df156a97edd636cf9d23498d0cfe7aec63e",
"licenses/dependencies/want-0.3.1/LICENSE": "a65f5d0a945d267751344c95665945b90c030ea107faf5c85d518929886187da",
"licenses/dependencies/web-time-1.1.0/LICENSE-APACHE": "54a744942eb3fa63a74d8d359989ed6962c04f3f10ff20cfa08ff8aa7efbe4e6",
"licenses/dependencies/web-time-1.1.0/LICENSE-MIT": "f428305bbf2e70fbd807af0f3c7ac1b7acfb95311640f451e9d2e48db6d7e96b",
"licenses/dependencies/webpki-roots-1.0.9/LICENSE": "e271993808fec50ab29350b39539cdec611a9103f827e0aa26d61da70e2d33f8",
"licenses/dependencies/wgpu-27.0.1/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-27.0.1/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-core-27.0.3/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-core-27.0.3/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-core-deps-windows-linux-android-27.0.0/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-core-deps-windows-linux-android-27.0.0/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-hal-27.0.4/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-hal-27.0.4/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/wgpu-types-27.0.1/LICENSE.APACHE": "a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9",
"licenses/dependencies/wgpu-types-27.0.1/LICENSE.MIT": "dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21",
"licenses/dependencies/winapi-util-0.1.11/COPYING": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
"licenses/dependencies/winapi-util-0.1.11/LICENSE-MIT": "cb3c929a05e6cbc9de9ab06a4c57eeb60ca8c724bef6c138c87d3a577e27aa14",
"licenses/dependencies/winapi-util-0.1.11/UNLICENSE": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
"licenses/dependencies/windows-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-core-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-core-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-implement-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-implement-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-interface-0.58.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-interface-0.58.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-link-0.2.1/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-link-0.2.1/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-result-0.2.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-result-0.2.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-strings-0.1.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-strings-0.1.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.52.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.52.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.59.0/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.59.0/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-sys-0.61.2/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-sys-0.61.2/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows-targets-0.52.6/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows-targets-0.52.6/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/windows_x86_64_gnullvm-0.52.6/license-apache-2.0": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
"licenses/dependencies/windows_x86_64_gnullvm-0.52.6/license-mit": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
"licenses/dependencies/window_clipboard-0.5.1/LICENSE": "7faec985f3e9b1c4a1df646bfedc304ba67e409447f7ab7f4f591f68708d85dc",
"licenses/dependencies/winit-0.30.13/LICENSE": "6dc0e068dcf3a5bc8e054205b85b7720e1d49265bbc64bf515d2cf79197df69a",
"licenses/dependencies/writeable-0.6.4/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/xml-rs-0.8.29/LICENSE": "0dc18d924dc0a5f41172a393012843a5eaaef338e795b3645da9cc3b6068220b",
"licenses/dependencies/yazi-0.2.1/LICENSE-APACHE": "7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c",
"licenses/dependencies/yazi-0.2.1/LICENSE-MIT": "df62e3ef3f207c91073fedd78b4156a278681d0dd3f942379242c62c6a71a3ec",
"licenses/dependencies/yoke-0.8.3/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/yoke-derive-0.8.2/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zeno-0.3.3/LICENSE-APACHE": "7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c",
"licenses/dependencies/zeno-0.3.3/LICENSE-MIT": "34dff8202d63e6df022f4f0ce88dab24f254c35ee0d5958b74dcf74d9eae21cc",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-APACHE": "9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-BSD": "83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32",
"licenses/dependencies/zerocopy-0.8.56/LICENSE-MIT": "1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-APACHE": "9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-BSD": "83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32",
"licenses/dependencies/zerocopy-derive-0.8.56/LICENSE-MIT": "1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df",
"licenses/dependencies/zerofrom-0.1.8/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerofrom-derive-0.1.7/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zeroize-1.9.0/LICENSE-APACHE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/zeroize-1.9.0/LICENSE-MIT": "8c7516d4b27b1e495be5e38b612298b63de48d05f49cdac94f70f3cd70f8864b",
"licenses/dependencies/zerotrie-0.2.5/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerovec-0.11.8/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zerovec-derive-0.11.6/LICENSE": "f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2",
"licenses/dependencies/zmij-1.0.23/LICENSE-MIT": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
"licenses/dependencies/clipboard-win-5.4.1/supplement/DoumanAsh-clipboard-win-3b27cf2bfd1a-LICENSE": "c9bff75738922193e67fa726fa225535870d2aa1059f91452c411736284ad566",
"licenses/dependencies/cosmic-text-0.15.0/fonts/FiraMono-LICENSE": "587dd9548304fd421cd254f7550bd101c1250ffc95417f2f7f92d55b44ecbe53",
"licenses/dependencies/cosmic-text-0.15.0/fonts/Inter-LICENSE": "3c8d13d97ea5eb62868833a377034c6be6a9833e768d32abec2a767a8101e4bc",
"licenses/dependencies/cosmic-text-0.15.0/fonts/NotoSans-LICENSE": "5ec4347054089def6904da61d04f0360968f9ef36634b1fe007a5b6ec2f7aa96",
"licenses/dependencies/fontdb-0.23.0/tests/fonts/LICENSE.txt": "b84fdd2c3da5db56385cdbb639795e90aa3e035c53bc3591135f18df3331451f",
"licenses/dependencies/gl_generator-0.14.0/supplement/brendanzab-gl-rs-ea503e8d5fb6-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/gpu-alloc-0.6.2/supplement/zakarumych-gpu-alloc-61020bdcb4eb-COPYING": "12121dfa588677007848ab922a45a1e3248868f6ff063598fceb3141d7897314",
"licenses/dependencies/gpu-alloc-types-0.3.1/supplement/zakarumych-gpu-alloc-7ddd1fe576fc-COPYING": "12121dfa588677007848ab922a45a1e3248868f6ff063598fceb3141d7897314",
"licenses/dependencies/gpu-descriptor-0.3.2/supplement/zakarumych-gpu-descriptor-bb28b4e55b74-COPYING": "f72143f7e9d9fb8bd336b139fa22f825a299591c29f2f7338c5566347b137613",
"licenses/dependencies/gpu-descriptor-types-0.2.0/supplement/zakarumych-gpu-descriptor-9f2fb9546591-COPYING": "f72143f7e9d9fb8bd336b139fa22f825a299591c29f2f7338c5566347b137613",
"licenses/dependencies/harfrust-0.3.2/scripts/ms-use/COPYING": "9906940f61b1f0b533fa7d99baf55178b2808fbe113ea51dfbfad8572ccd5f2b",
"licenses/dependencies/hexf-parse-0.2.1/supplement/CC0-1.0.txt": "a2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499",
"licenses/dependencies/hexf-parse-0.2.1/supplement/hexf-parse-0.2.1-Cargo.toml": "4a56dbdbc12054fd33b7a2634a45cbbe6fe12f5e6f4081002cbfa527f7220c70",
"licenses/dependencies/iced_core-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_core-0.14.0/src/layout/DRUID_LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/iced_debug-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_futures-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_graphics-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_graphics-0.14.0/assets/FiraSans-Regular.ttf/Fira-OFL.txt": "99bfb7c1e845b79d1031fcf37e678178eb4a8c7cc74a3f218ddf7223083a6fcd",
"licenses/dependencies/iced_graphics-0.14.0/assets/FiraSans-Regular.ttf/FiraSans-Regular-NOTICE.txt": "1e0baaa389b1647d06322ac9ea37822f31995408200ae5a2805a6b9bea0810d1",
"licenses/dependencies/iced_graphics-0.14.0/assets/Iced-Icons.ttf/Iced-Icons-NOTICE.txt": "8175634e30f84ef72a24c4965fb0e87f45a3c1274cc0e79e0473af582cffd1c4",
"licenses/dependencies/iced_graphics-0.14.0/assets/Iced-Icons.ttf/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_program-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_renderer-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_runtime-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_tiny_skia-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_wgpu-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_widget-0.14.2/supplement/iced-rs-iced-54abf81d13fe-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/iced_winit-0.14.0/supplement/iced-rs-iced-3997291f318a-LICENSE": "fc9086ba4eba4b77e4c603906362742bc3715ffa2c7810c6074fe7780d3a0398",
"licenses/dependencies/khronos_api-3.1.0/supplement/brendanzab-gl-rs-f150967b1c44-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/lyon-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_algorithms-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_algorithms-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_geom-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_geom-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_path-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_path-1.0.19/supplement/nical-lyon-56219c95c658-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/lyon_tessellation-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-APACHE": "216486f29671a4262efe32af6d84a75bef398127f8c5f369b5c8305983887a06",
"licenses/dependencies/lyon_tessellation-1.0.21/supplement/nical-lyon-994526f2766c-LICENSE-MIT": "80f275e90d799911ed3830a7f242a2ef5a4ade2092fe0aa07bfb2d2cf2f2b95e",
"licenses/dependencies/profiling-1.0.18/supplement/aclysma-profiling-8271551172eb-LICENSE-APACHE": "10d30a673cd5e9349bdc02aeb48f14b3386d27d0da32df8f0a555d4aa16aa551",
"licenses/dependencies/profiling-1.0.18/supplement/aclysma-profiling-8271551172eb-LICENSE-MIT": "c8167fdeeed46d3f244d3f85c5bf998ce889343691c32be2c61a8bc4b5c08333",
"licenses/dependencies/ring-0.17.14/src/polyfill/once_cell/LICENSE-APACHE": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
"licenses/dependencies/ring-0.17.14/src/polyfill/once_cell/LICENSE-MIT": "6ee2ed6c77710de911761acd5fc1ad1da00f476beb1a7ef27e78c2d1858deafc",
"licenses/dependencies/ring-0.17.14/third_party/fiat/LICENSE": "9eacbcb81be660840c714a560a9d65ba07913db98dd4baf969f78dd499fdd60f",
"licenses/dependencies/spirv-0.3.0+sdk-1.3.268.0/supplement/gfx-rs-rspirv-e91a5debc10c-LICENSE": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
"licenses/dependencies/svg_fmt-0.4.5/supplement/nical-rust_debug-93f414cd572b-LICENSE": "7e98bed7f100747aaae7d82ab94fbe6b76fd6b84b09a3aaa413bff8196d0fbb1",
"licenses/dependencies/tracing-core-0.1.36/src/spin/LICENSE": "58545fed1565e42d687aecec6897d35c6d37ccb71479a137c0deb2203e125c79",
"licenses/dependencies/ttf-parser-0.25.1/tests/fonts/colr_1_LICENSE": "58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd"
}
@@ -0,0 +1,5 @@
{
"notes.arcadia": "ad9de02963c20d1f43856455a797deb05ca674659e45f2c4b96b52783024f8bd",
"project.arcadia": "b1fd5349f956f3a17005f883c6675c73aee0f6bcee2b9fa7a582996215c3b23e",
"oa/activities/activity_assess_incident_work.arcadia": "0bb8947810cf9a8bcb9394bf72ca512f9da5bf9128262188510367455291b1d7"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

@@ -0,0 +1,12 @@
{
"atUtc": "2026-09-11T16:48:57.166281+00:00",
"args": [
"check",
"lifeline",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\harness\\fixtures\\staged-source-authoring\\base\\project.arcadia",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\checkpoint-first\\project.arcadia",
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\contextual-prerelease-gui-20260911-v2\\checkpoint-first\\project.arcadia"
],
"exitCode": 0,
"oracleSha256": "967d9ba3c6fb3a7efb410833903ec94556ca2d48a67d5072c8bb160f40a00f9c"
}

Some files were not shown because too many files have changed in this diff Show More