Automate issuer overlay creation from ticker searches

This commit is contained in:
2026-03-19 20:44:58 -04:00
parent 17de3dd72d
commit 391d6d34ce
79 changed files with 4746 additions and 695 deletions

View File

@@ -6,6 +6,7 @@ use regex::Regex;
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fs;
use std::sync::Mutex;
use std::time::{Duration, Instant};
@@ -17,7 +18,7 @@ mod surface_mapper;
mod taxonomy_loader;
mod universal_income;
use taxonomy_loader::{ComputationSpec, ComputedDefinition};
use taxonomy_loader::{ComputationSpec, ComputedDefinition, RuntimeIssuerOverlay, SurfacePackFile};
pub const PARSER_ENGINE: &str = "fiscal-xbrl";
pub const PARSER_VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -26,6 +27,316 @@ const DEFAULT_SEC_RATE_LIMIT_MS: u64 = 100;
const HTTP_TIMEOUT_SECS: u64 = 30;
static RATE_LIMITER: Lazy<Mutex<Instant>> = Lazy::new(|| Mutex::new(Instant::now()));
static PRIMARY_STATEMENT_CONCEPT_INDEX: Lazy<PrimaryStatementConceptIndex> =
Lazy::new(load_primary_statement_concept_index);
#[derive(Debug, Default, Clone)]
struct SurfaceConceptIndex {
primary_by_qname: HashMap<String, HashSet<String>>,
primary_by_local_name: HashMap<String, HashSet<String>>,
disclosure_by_qname: HashMap<String, HashSet<String>>,
disclosure_by_local_name: HashMap<String, HashSet<String>>,
}
#[derive(Debug, Default, Clone)]
struct SurfaceConceptMembership {
primary_statements: HashSet<String>,
disclosure_surfaces: HashSet<String>,
}
impl SurfaceConceptIndex {
fn insert(&mut self, concept: &str, statement: &str, surface_key: &str) {
let Some(normalized_concept) = normalize_taxonomy_identity(concept) else {
return;
};
let Some(local_name) = normalize_taxonomy_local_name(concept) else {
return;
};
if statement == "disclosure" {
self.disclosure_by_qname
.entry(normalized_concept)
.or_default()
.insert(surface_key.to_string());
self.disclosure_by_local_name
.entry(local_name)
.or_default()
.insert(surface_key.to_string());
return;
}
if !is_primary_statement_kind(statement) {
return;
}
self.primary_by_qname
.entry(normalized_concept)
.or_default()
.insert(statement.to_string());
self.primary_by_local_name
.entry(local_name)
.or_default()
.insert(statement.to_string());
}
fn membership_for(&self, qname: &str, local_name: &str) -> SurfaceConceptMembership {
let mut membership = SurfaceConceptMembership::default();
if let Some(statement) = statement_overlap_override(local_name) {
membership.primary_statements.insert(statement.to_string());
}
for value in self
.resolve_from_map(&self.primary_by_qname, qname)
.into_iter()
.flatten()
{
membership.primary_statements.insert(value);
}
for value in self
.resolve_from_map(&self.primary_by_local_name, local_name)
.into_iter()
.flatten()
{
membership.primary_statements.insert(value);
}
for value in self
.resolve_from_map(&self.disclosure_by_qname, qname)
.into_iter()
.flatten()
{
membership.disclosure_surfaces.insert(value);
}
for value in self
.resolve_from_map(&self.disclosure_by_local_name, local_name)
.into_iter()
.flatten()
{
membership.disclosure_surfaces.insert(value);
}
membership
}
fn resolve_primary_statement(&self, qname: &str, local_name: &str) -> Option<String> {
if let Some(statement) = statement_overlap_override(local_name) {
return Some(statement.to_string());
}
self.resolve_unique_from_map(&self.primary_by_qname, qname)
.or_else(|| self.resolve_unique_from_map(&self.primary_by_local_name, local_name))
}
fn resolve_unique_from_map(
&self,
map: &HashMap<String, HashSet<String>>,
value: &str,
) -> Option<String> {
let normalized = normalize_taxonomy_identity(value)?;
let statements = map.get(&normalized)?;
if statements.len() != 1 {
return None;
}
statements.iter().next().cloned()
}
fn resolve_from_map(
&self,
map: &HashMap<String, HashSet<String>>,
value: &str,
) -> Option<HashSet<String>> {
let normalized = normalize_taxonomy_identity(value)?;
map.get(&normalized).cloned()
}
}
#[derive(Debug, Default)]
struct PrimaryStatementConceptIndex {
by_qname: HashMap<String, HashSet<String>>,
by_local_name: HashMap<String, HashSet<String>>,
}
impl PrimaryStatementConceptIndex {
fn insert(&mut self, concept: &str, statement: &str) {
if !is_primary_statement_kind(statement) {
return;
}
let Some(normalized_concept) = normalize_taxonomy_identity(concept) else {
return;
};
self.by_qname
.entry(normalized_concept)
.or_default()
.insert(statement.to_string());
let Some(local_name) = normalize_taxonomy_local_name(concept) else {
return;
};
self.by_local_name
.entry(local_name)
.or_default()
.insert(statement.to_string());
}
fn resolve(&self, qname: &str, local_name: &str) -> Option<String> {
if let Some(statement) = statement_overlap_override(local_name) {
return Some(statement.to_string());
}
self.resolve_from_map(&self.by_qname, qname)
.or_else(|| self.resolve_from_map(&self.by_local_name, local_name))
}
fn resolve_from_map(
&self,
map: &HashMap<String, HashSet<String>>,
value: &str,
) -> Option<String> {
let normalized = normalize_taxonomy_identity(value)?;
let statements = map.get(&normalized)?;
if statements.len() != 1 {
return None;
}
statements.iter().next().cloned()
}
}
fn is_primary_statement_kind(statement: &str) -> bool {
matches!(
statement,
"income" | "balance" | "cash_flow" | "equity" | "comprehensive_income"
)
}
fn normalize_taxonomy_identity(value: &str) -> Option<String> {
let trimmed = value.trim().to_ascii_lowercase();
if trimmed.is_empty() {
None
} else {
Some(trimmed)
}
}
fn normalize_taxonomy_local_name(value: &str) -> Option<String> {
let normalized = normalize_taxonomy_identity(value)?;
let local_name = normalized
.rsplit_once(':')
.map(|(_, local_name)| local_name)
.unwrap_or(normalized.as_str())
.trim()
.to_string();
if local_name.is_empty() {
None
} else {
Some(local_name)
}
}
fn statement_overlap_override(local_name: &str) -> Option<&'static str> {
match normalize_taxonomy_local_name(local_name).as_deref() {
Some("stockholdersequity") => Some("equity"),
Some("retainedearningsaccumulateddeficit") => Some("equity"),
Some("commonstocksincludingadditionalpaidincapital") => Some("equity"),
Some("accumulatedothercomprehensiveincomelossnetoftax") => Some("equity"),
Some("stockholdersequityother") => Some("equity"),
Some("liabilitiesandstockholdersequity") => Some("balance"),
_ => None,
}
}
fn load_primary_statement_concept_index() -> PrimaryStatementConceptIndex {
let mut index = PrimaryStatementConceptIndex::default();
let taxonomy_dir = match taxonomy_loader::resolve_taxonomy_dir() {
Ok(path) => path,
Err(error) => {
eprintln!("[fiscal-xbrl] primary statement taxonomy index unavailable: {error}");
return index;
}
};
let fiscal_dir = taxonomy_dir.join("fiscal").join("v1");
let entries = match fs::read_dir(&fiscal_dir) {
Ok(entries) => entries,
Err(error) => {
eprintln!(
"[fiscal-xbrl] unable to read taxonomy surface directory {}: {error}",
fiscal_dir.display()
);
return index;
}
};
for entry in entries.flatten() {
let path = entry.path();
let file_name = path
.file_name()
.and_then(|value| value.to_str())
.unwrap_or("");
if !file_name.ends_with(".surface.json") || file_name == "universal_income.surface.json" {
continue;
}
let raw = match fs::read_to_string(&path) {
Ok(raw) => raw,
Err(error) => {
eprintln!(
"[fiscal-xbrl] unable to read surface taxonomy {}: {error}",
path.display()
);
continue;
}
};
let pack = match serde_json::from_str::<SurfacePackFile>(&raw) {
Ok(pack) => pack,
Err(error) => {
eprintln!(
"[fiscal-xbrl] unable to parse surface taxonomy {}: {error}",
path.display()
);
continue;
}
};
for surface in pack
.surfaces
.iter()
.filter(|surface| is_primary_statement_kind(&surface.statement))
{
for concept in surface
.allowed_source_concepts
.iter()
.chain(surface.allowed_authoritative_concepts.iter())
{
index.insert(concept, &surface.statement);
}
}
}
index
}
fn build_surface_concept_index(surface_pack: &SurfacePackFile) -> SurfaceConceptIndex {
let mut index = SurfaceConceptIndex::default();
for surface in &surface_pack.surfaces {
for concept in surface
.allowed_source_concepts
.iter()
.chain(surface.allowed_authoritative_concepts.iter())
.chain(surface.issuer_overlay_source_concepts.iter())
.chain(surface.issuer_overlay_authoritative_concepts.iter())
{
index.insert(concept, &surface.statement, &surface.surface_key);
}
}
index
}
fn sec_rate_limit_delay() -> u64 {
std::env::var("SEC_RATE_LIMIT_MS")
@@ -89,6 +400,8 @@ pub struct HydrateFilingRequest {
pub filing_type: String,
pub filing_url: Option<String>,
pub primary_document: Option<String>,
#[serde(default)]
pub issuer_overlay: Option<RuntimeIssuerOverlay>,
pub cache_dir: Option<String>,
}
@@ -420,6 +733,10 @@ pub struct NormalizationSummaryOutput {
pub kpi_row_count: usize,
pub unmapped_row_count: usize,
pub material_unmapped_row_count: usize,
pub residual_primary_count: usize,
pub residual_disclosure_count: usize,
pub unsupported_concept_count: usize,
pub issuer_overlay_match_count: usize,
pub warnings: Vec<String>,
}
@@ -520,6 +837,10 @@ pub fn hydrate_filing(input: HydrateFilingRequest) -> Result<HydrateFilingRespon
kpi_row_count: 0,
unmapped_row_count: 0,
material_unmapped_row_count: 0,
residual_primary_count: 0,
residual_disclosure_count: 0,
unsupported_concept_count: 0,
issuer_overlay_match_count: 0,
warnings: vec![],
},
});
@@ -571,6 +892,27 @@ pub fn hydrate_filing(input: HydrateFilingRequest) -> Result<HydrateFilingRespon
}
}
let initial_materialized = materialize_taxonomy_statements(
input.filing_id,
&input.accession_number,
&input.filing_date,
&input.filing_type,
&parsed_instance.facts,
&presentation,
&label_by_concept,
None,
);
let taxonomy_regime = infer_taxonomy_regime(&parsed_instance.facts);
let pack_selection = pack_selector::select_fiscal_pack(
&initial_materialized.statement_rows,
&initial_materialized.facts,
);
let surface_pack = taxonomy_loader::load_surface_pack_with_overlays(
pack_selection.pack,
Some(&input.ticker),
input.issuer_overlay.as_ref(),
)?;
let surface_concept_index = build_surface_concept_index(&surface_pack);
let materialized = materialize_taxonomy_statements(
input.filing_id,
&input.accession_number,
@@ -579,19 +921,23 @@ pub fn hydrate_filing(input: HydrateFilingRequest) -> Result<HydrateFilingRespon
&parsed_instance.facts,
&presentation,
&label_by_concept,
Some(&surface_concept_index),
);
let taxonomy_regime = infer_taxonomy_regime(&parsed_instance.facts);
let mut concepts = materialized.concepts;
let mut facts = materialized.facts;
let pack_selection = pack_selector::select_fiscal_pack(&materialized.statement_rows, &facts);
let fiscal_pack = pack_selection.pack.as_str().to_string();
let mut compact_model = surface_mapper::build_compact_surface_model(
&materialized.periods,
&materialized.statement_rows,
&taxonomy_regime,
pack_selection.pack,
Some(&input.ticker),
input.issuer_overlay.as_ref(),
pack_selection.warnings,
)?;
compact_model
.normalization_summary
.unsupported_concept_count = materialized.unsupported_concept_count;
universal_income::apply_universal_income_rows(
&materialized.periods,
&materialized.statement_rows,
@@ -1465,6 +1811,7 @@ struct MaterializedStatements {
statement_rows: StatementRowMap,
concepts: Vec<ConceptOutput>,
facts: Vec<FactOutput>,
unsupported_concept_count: usize,
}
fn materialize_taxonomy_statements(
@@ -1475,6 +1822,7 @@ fn materialize_taxonomy_statements(
facts: &[ParsedFact],
presentation: &[PresentationNode],
label_by_concept: &HashMap<String, String>,
surface_index: Option<&SurfaceConceptIndex>,
) -> MaterializedStatements {
let compact_accession = accession_number.replace('-', "");
let mut period_by_signature = HashMap::<String, PeriodOutput>::new();
@@ -1551,6 +1899,7 @@ fn materialize_taxonomy_statements(
let mut grouped_by_statement = empty_parsed_fact_map();
let mut enriched_facts = Vec::new();
let mut unsupported_concepts = HashSet::<String>::new();
for (index, fact) in facts.iter().enumerate() {
let nodes = presentation_by_concept
@@ -1558,9 +1907,28 @@ fn materialize_taxonomy_statements(
.cloned()
.unwrap_or_default();
let best_node = nodes.first().copied();
let statement_kind = best_node
.and_then(|node| classify_statement_role(&node.role_uri))
.or_else(|| concept_statement_fallback(&fact.local_name));
let role_statement_kind =
best_node.and_then(|node| classify_statement_role(&node.role_uri));
let disclosure_role_family =
best_node.and_then(|node| classify_disclosure_role(&node.role_uri));
let statement_kind = if let Some(statement_kind) = role_statement_kind {
Some(statement_kind)
} else if disclosure_role_family.is_some() {
Some("disclosure".to_string())
} else if let Some(index) = surface_index {
let membership = index.membership_for(&fact.qname, &fact.local_name);
if !membership.disclosure_surfaces.is_empty() {
Some("disclosure".to_string())
} else {
index.resolve_primary_statement(&fact.qname, &fact.local_name)
}
} else {
concept_statement_fallback(&fact.qname, &fact.local_name)
};
if statement_kind.is_none() {
unsupported_concepts.insert(fact.concept_key.clone());
}
let fact_output = FactOutput {
concept_key: fact.concept_key.clone(),
@@ -1762,6 +2130,7 @@ fn materialize_taxonomy_statements(
statement_rows,
concepts,
facts: enriched_facts,
unsupported_concept_count: unsupported_concepts.len(),
}
}
@@ -1795,11 +2164,12 @@ fn empty_detail_row_map() -> DetailRowStatementMap {
.collect()
}
fn statement_keys() -> [&'static str; 5] {
fn statement_keys() -> [&'static str; 6] {
[
"income",
"balance",
"cash_flow",
"disclosure",
"equity",
"comprehensive_income",
]
@@ -1810,6 +2180,7 @@ fn statement_key_ref(value: &str) -> Option<&'static str> {
"income" => Some("income"),
"balance" => Some("balance"),
"cash_flow" => Some("cash_flow"),
"disclosure" => Some("disclosure"),
"equity" => Some("equity"),
"comprehensive_income" => Some("comprehensive_income"),
_ => None,
@@ -1913,52 +2284,62 @@ fn classify_statement_role(role_uri: &str) -> Option<String> {
None
}
fn concept_statement_fallback(local_name: &str) -> Option<String> {
let normalized = local_name.to_ascii_lowercase();
if Regex::new(r#"equity|retainedearnings|additionalpaidincapital"#)
.unwrap()
.is_match(&normalized)
pub fn classify_disclosure_role(role_uri: &str) -> Option<String> {
let normalized = role_uri.to_ascii_lowercase();
if normalized.contains("tax") {
return Some("income_tax_disclosure".to_string());
}
if normalized.contains("debt")
|| normalized.contains("borrow")
|| normalized.contains("notespayable")
{
return Some("equity".to_string());
return Some("debt_disclosure".to_string());
}
if normalized.contains("comprehensiveincome") {
return Some("comprehensive_income".to_string());
if normalized.contains("lease") {
return Some("lease_disclosure".to_string());
}
if Regex::new(
r#"deferredpolicyacquisitioncosts(andvalueofbusinessacquired)?$|supplementaryinsuranceinformationdeferredpolicyacquisitioncosts$|deferredacquisitioncosts$"#,
)
.unwrap()
.is_match(&normalized)
if normalized.contains("derivative") || normalized.contains("hedg") {
return Some("derivative_instruments_disclosure".to_string());
}
if normalized.contains("intangible") || normalized.contains("goodwill") {
return Some("intangible_assets_disclosure".to_string());
}
if normalized.contains("revenue")
|| normalized.contains("performanceobligation")
|| normalized.contains("contractwithcustomer")
{
return Some("balance".to_string());
return Some("revenue_disclosure".to_string());
}
if Regex::new(
r#"netcashprovidedbyusedin.*activities|increasedecreasein|paymentstoacquire|paymentsforcapitalimprovements$|paymentsfordepositsonrealestateacquisitions$|paymentsforrepurchase|paymentsofdividends|dividendscommonstockcash$|proceedsfrom|repaymentsofdebt|sharebasedcompensation$|allocatedsharebasedcompensationexpense$|depreciationdepletionandamortization$|depreciationamortizationandaccretionnet$|depreciationandamortization$|depreciationamortizationandother$|otheradjustmentstoreconcilenetincomelosstocashprovidedbyusedinoperatingactivities"#,
)
.unwrap()
.is_match(&normalized)
if normalized.contains("restrictedcash") {
return Some("cash_flow_disclosure".to_string());
}
if normalized.contains("businesscombination")
|| normalized.contains("acquisition")
|| normalized.contains("purchaseprice")
{
return Some("cash_flow".to_string());
return Some("business_combinations_disclosure".to_string());
}
if Regex::new(
r#"asset|liabilit|debt|financingreceivable|loansreceivable|deposits|allowanceforcreditloss|futurepolicybenefits|policyholderaccountbalances|unearnedpremiums|realestateinvestmentproperty|grossatcarryingvalue|investmentproperty"#,
)
.unwrap()
.is_match(&normalized)
{
return Some("balance".to_string());
if normalized.contains("sharebased") || normalized.contains("stockcompensation") {
return Some("share_based_compensation_disclosure".to_string());
}
if Regex::new(
r#"revenue|income|profit|expense|costof|leaseincome|rental|premiums|claims|underwriting|policyacquisition|interestincome|interestexpense|noninterest|leasedandrentedproperty"#,
)
.unwrap()
.is_match(&normalized)
{
return Some("income".to_string());
if normalized.contains("equitymethod") || normalized.contains("equitysecurity") {
return Some("equity_investments_disclosure".to_string());
}
if normalized.contains("deferredtax") {
return Some("deferred_tax_balance_disclosure".to_string());
}
if normalized.contains("othercomprehensiveincome") || normalized.contains("oci") {
return Some("other_comprehensive_income_disclosure".to_string());
}
None
}
fn concept_statement_fallback(qname: &str, local_name: &str) -> Option<String> {
PRIMARY_STATEMENT_CONCEPT_INDEX.resolve(qname, local_name)
}
fn is_standard_namespace(namespace_uri: &str) -> bool {
let lower = namespace_uri.to_ascii_lowercase();
lower.contains("us-gaap")
@@ -2110,6 +2491,8 @@ mod tests {
&statement_rows,
"us-gaap",
FiscalPack::Core,
None,
None,
vec![],
)
.expect("core pack should load and map");
@@ -2218,60 +2601,124 @@ mod tests {
fn classifies_pack_specific_concepts_without_presentation_roles() {
assert_eq!(
concept_statement_fallback(
"us-gaap:FinancingReceivableExcludingAccruedInterestAfterAllowanceForCreditLoss",
"FinancingReceivableExcludingAccruedInterestAfterAllowanceForCreditLoss"
)
.as_deref(),
Some("balance")
);
assert_eq!(
concept_statement_fallback("Deposits").as_deref(),
concept_statement_fallback("us-gaap:Deposits", "Deposits").as_deref(),
Some("balance")
);
assert_eq!(
concept_statement_fallback("RealEstateInvestmentPropertyNet").as_deref(),
concept_statement_fallback(
"us-gaap:RealEstateInvestmentPropertyNet",
"RealEstateInvestmentPropertyNet"
)
.as_deref(),
Some("balance")
);
assert_eq!(
concept_statement_fallback("DeferredPolicyAcquisitionCosts").as_deref(),
concept_statement_fallback(
"us-gaap:DeferredPolicyAcquisitionCosts",
"DeferredPolicyAcquisitionCosts"
)
.as_deref(),
Some("balance")
);
assert_eq!(
concept_statement_fallback("DeferredPolicyAcquisitionCostsAndValueOfBusinessAcquired")
concept_statement_fallback(
"us-gaap:DeferredPolicyAcquisitionCostsAndValueOfBusinessAcquired",
"DeferredPolicyAcquisitionCostsAndValueOfBusinessAcquired"
)
.as_deref(),
Some("balance")
);
assert_eq!(
concept_statement_fallback(
"us-gaap:IncreaseDecreaseInAccountsReceivable",
"IncreaseDecreaseInAccountsReceivable"
)
.as_deref(),
Some("cash_flow")
);
assert_eq!(
concept_statement_fallback("us-gaap:PaymentsOfDividends", "PaymentsOfDividends")
.as_deref(),
Some("balance")
);
assert_eq!(
concept_statement_fallback("IncreaseDecreaseInAccountsReceivable").as_deref(),
Some("cash_flow")
);
assert_eq!(
concept_statement_fallback("PaymentsOfDividends").as_deref(),
concept_statement_fallback("us-gaap:RepaymentsOfDebt", "RepaymentsOfDebt").as_deref(),
Some("cash_flow")
);
assert_eq!(
concept_statement_fallback("RepaymentsOfDebt").as_deref(),
concept_statement_fallback("us-gaap:ShareBasedCompensation", "ShareBasedCompensation")
.as_deref(),
None
);
assert_eq!(
concept_statement_fallback(
"us-gaap:PaymentsForCapitalImprovements",
"PaymentsForCapitalImprovements"
)
.as_deref(),
Some("cash_flow")
);
assert_eq!(
concept_statement_fallback("ShareBasedCompensation").as_deref(),
concept_statement_fallback(
"us-gaap:PaymentsForDepositsOnRealEstateAcquisitions",
"PaymentsForDepositsOnRealEstateAcquisitions"
)
.as_deref(),
Some("cash_flow")
);
assert_eq!(
concept_statement_fallback("PaymentsForCapitalImprovements").as_deref(),
Some("cash_flow")
);
assert_eq!(
concept_statement_fallback("PaymentsForDepositsOnRealEstateAcquisitions").as_deref(),
Some("cash_flow")
);
assert_eq!(
concept_statement_fallback("LeaseIncome").as_deref(),
concept_statement_fallback("us-gaap:LeaseIncome", "LeaseIncome").as_deref(),
Some("income")
);
assert_eq!(
concept_statement_fallback("DirectCostsOfLeasedAndRentedPropertyOrEquipment")
.as_deref(),
concept_statement_fallback(
"us-gaap:DirectCostsOfLeasedAndRentedPropertyOrEquipment",
"DirectCostsOfLeasedAndRentedPropertyOrEquipment"
)
.as_deref(),
Some("income")
);
}
#[test]
fn keeps_disclosure_only_concepts_out_of_primary_statement_fallback() {
assert_eq!(
concept_statement_fallback(
"us-gaap:RevenueRemainingPerformanceObligation",
"RevenueRemainingPerformanceObligation"
),
None
);
assert_eq!(
concept_statement_fallback(
"us-gaap:EquitySecuritiesFVNINoncurrent",
"EquitySecuritiesFVNINoncurrent"
),
None
);
}
#[test]
fn applies_explicit_balance_equity_overlap_overrides() {
assert_eq!(
concept_statement_fallback("us-gaap:StockholdersEquity", "StockholdersEquity")
.as_deref(),
Some("equity")
);
assert_eq!(
concept_statement_fallback(
"us-gaap:LiabilitiesAndStockholdersEquity",
"LiabilitiesAndStockholdersEquity"
)
.as_deref(),
Some("balance")
);
}
}

View File

@@ -3,8 +3,9 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use crate::pack_selector::FiscalPack;
use crate::taxonomy_loader::{
load_crosswalk, load_income_bridge, load_surface_pack, CrosswalkFile, IncomeBridgeFile,
IncomeBridgeRow, SurfaceDefinition, SurfaceFormula, SurfaceFormulaOp, SurfaceSignTransform,
load_crosswalk, load_income_bridge, load_surface_pack_with_overlays, CrosswalkFile,
IncomeBridgeFile, IncomeBridgeRow, RuntimeIssuerOverlay, SurfaceDefinition, SurfaceFormula,
SurfaceFormulaOp, SurfaceOrigin, SurfaceSignTransform,
};
use crate::{
ConceptOutput, DetailRowOutput, DetailRowStatementMap, FactOutput, NormalizationSummaryOutput,
@@ -63,6 +64,7 @@ struct MatchedStatementRow<'a> {
mapping_method: MappingMethod,
match_role: MatchRole,
rank: i64,
issuer_overlay_match: bool,
}
#[derive(Debug, Default, Clone)]
@@ -110,9 +112,11 @@ pub fn build_compact_surface_model(
statement_rows: &StatementRowMap,
taxonomy_regime: &str,
fiscal_pack: FiscalPack,
ticker: Option<&str>,
runtime_overlay: Option<&RuntimeIssuerOverlay>,
warnings: Vec<String>,
) -> Result<CompactSurfaceModel> {
let pack = load_surface_pack(fiscal_pack)?;
let pack = load_surface_pack_with_overlays(fiscal_pack, ticker, runtime_overlay)?;
let crosswalk = load_crosswalk(taxonomy_regime)?;
let income_bridge = load_income_bridge(fiscal_pack).ok();
let mut surface_rows = empty_surface_row_map();
@@ -122,6 +126,9 @@ pub fn build_compact_surface_model(
let mut detail_row_count = 0usize;
let mut unmapped_row_count = 0usize;
let mut material_unmapped_row_count = 0usize;
let mut residual_primary_count = 0usize;
let mut residual_disclosure_count = 0usize;
let mut issuer_overlay_match_keys = HashSet::<String>::new();
for statement in statement_keys() {
let rows = statement_rows.get(statement).cloned().unwrap_or_default();
@@ -130,6 +137,11 @@ pub fn build_compact_surface_model(
.iter()
.filter(|definition| definition.statement == statement)
.collect::<Vec<_>>();
if statement_definitions.is_empty() {
surface_rows.insert(statement.to_string(), Vec::new());
detail_rows.insert(statement.to_string(), BTreeMap::new());
continue;
}
statement_definitions.sort_by(|left, right| {
left.order
.cmp(&right.order)
@@ -203,6 +215,9 @@ pub fn build_compact_surface_model(
residual_flag: false,
},
);
if matched.issuer_overlay_match {
issuer_overlay_match_keys.insert(matched.row.concept_key.clone());
}
}
let details = detail_matches
@@ -221,6 +236,9 @@ pub fn build_compact_surface_model(
residual_flag: false,
},
);
if matched.issuer_overlay_match {
issuer_overlay_match_keys.insert(matched.row.concept_key.clone());
}
build_detail_row(
matched.row,
&definition.surface_key,
@@ -310,6 +328,11 @@ pub fn build_compact_surface_model(
if !residual_rows.is_empty() {
unmapped_row_count += residual_rows.len();
if statement == "disclosure" {
residual_disclosure_count += residual_rows.len();
} else {
residual_primary_count += residual_rows.len();
}
material_unmapped_row_count += residual_rows
.iter()
.filter(|row| max_abs_value(&row.values) >= threshold)
@@ -331,6 +354,10 @@ pub fn build_compact_surface_model(
kpi_row_count: 0,
unmapped_row_count,
material_unmapped_row_count,
residual_primary_count,
residual_disclosure_count,
unsupported_concept_count: 0,
issuer_overlay_match_count: issuer_overlay_match_keys.len(),
warnings,
},
concept_mappings,
@@ -734,21 +761,38 @@ fn match_statement_row<'a>(
}) || authoritative_mapping
.map(|mapping| mapping.surface_key == definition.surface_key)
.unwrap_or(false);
let matches_overlay_authoritative =
authoritative_concept_key.as_ref().map_or(false, |concept| {
definition
.issuer_overlay_authoritative_concepts
.iter()
.any(|candidate| candidate_matches(candidate, concept))
});
if matches_authoritative {
if matches_authoritative || matches_overlay_authoritative {
return Some(MatchedStatementRow {
row,
authoritative_concept_key,
mapping_method: MappingMethod::AuthoritativeDirect,
match_role: MatchRole::Surface,
rank: 0,
issuer_overlay_match: matches_overlay_authoritative
|| definition.origin == SurfaceOrigin::IssuerOverlay,
});
}
let matches_source = definition.allowed_source_concepts.iter().any(|candidate| {
candidate_matches(candidate, &row.qname) || candidate_matches(candidate, &row.local_name)
});
if matches_source {
let matches_overlay_source =
definition
.issuer_overlay_source_concepts
.iter()
.any(|candidate| {
candidate_matches(candidate, &row.qname)
|| candidate_matches(candidate, &row.local_name)
});
if matches_source || matches_overlay_source {
return Some(MatchedStatementRow {
row,
authoritative_concept_key,
@@ -759,6 +803,8 @@ fn match_statement_row<'a>(
MatchRole::Surface
},
rank: 1,
issuer_overlay_match: matches_overlay_source
|| definition.origin == SurfaceOrigin::IssuerOverlay,
});
}
@@ -832,6 +878,7 @@ fn match_income_bridge_detail_row<'a>(
mapping_method: MappingMethod::AggregateChildren,
match_role: MatchRole::Detail,
rank: 2,
issuer_overlay_match: false,
})
}
@@ -1033,11 +1080,12 @@ fn candidate_matches(candidate: &str, actual: &str) -> bool {
.unwrap_or(false)
}
fn statement_keys() -> [&'static str; 5] {
fn statement_keys() -> [&'static str; 6] {
[
"income",
"balance",
"cash_flow",
"disclosure",
"equity",
"comprehensive_income",
]
@@ -1122,6 +1170,7 @@ mod tests {
("income".to_string(), Vec::new()),
("balance".to_string(), Vec::new()),
("cash_flow".to_string(), Vec::new()),
("disclosure".to_string(), Vec::new()),
("equity".to_string(), Vec::new()),
("comprehensive_income".to_string(), Vec::new()),
])
@@ -1151,6 +1200,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Core,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1178,6 +1229,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Core,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1220,6 +1273,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Core,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1290,9 +1345,16 @@ mod tests {
},
];
let model =
build_compact_surface_model(&periods, &rows, "us-gaap", FiscalPack::Core, vec![])
.expect("compact model should build");
let model = build_compact_surface_model(
&periods,
&rows,
"us-gaap",
FiscalPack::Core,
None,
None,
vec![],
)
.expect("compact model should build");
let receivables = model
.surface_rows
@@ -1365,6 +1427,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Core,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1430,6 +1494,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::BankLender,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1473,6 +1539,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Insurance,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1557,6 +1625,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Core,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1640,6 +1710,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Core,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1686,6 +1758,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Insurance,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1742,6 +1816,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::ReitRealEstate,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1786,6 +1862,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::Software,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1825,6 +1903,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::EntertainmentBroadcasters,
None,
None,
vec![],
)
.expect("compact model should build");
@@ -1866,6 +1946,8 @@ mod tests {
&rows,
"us-gaap",
FiscalPack::PlanDefinedBenefit,
None,
None,
vec![],
)
.expect("compact model should build");

View File

@@ -11,6 +11,19 @@ fn default_include_in_output() -> bool {
true
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SurfaceOrigin {
PackPrimary,
PackDisclosure,
CorePrimary,
CoreDisclosure,
IssuerOverlay,
}
fn default_surface_origin() -> SurfaceOrigin {
SurfaceOrigin::CorePrimary
}
#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SurfaceSignTransform {
@@ -25,6 +38,25 @@ pub struct SurfacePackFile {
pub surfaces: Vec<SurfaceDefinition>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct RuntimeIssuerOverlay {
pub version: String,
pub ticker: String,
pub pack: Option<String>,
#[serde(default)]
pub mappings: Vec<RuntimeIssuerOverlayMapping>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct RuntimeIssuerOverlayMapping {
pub surface_key: String,
pub statement: String,
#[serde(default)]
pub allowed_source_concepts: Vec<String>,
#[serde(default)]
pub allowed_authoritative_concepts: Vec<String>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct SurfaceDefinition {
pub surface_key: String,
@@ -43,6 +75,12 @@ pub struct SurfaceDefinition {
pub include_in_output: bool,
#[serde(default)]
pub sign_transform: Option<SurfaceSignTransform>,
#[serde(skip, default = "default_surface_origin")]
pub origin: SurfaceOrigin,
#[serde(skip, default)]
pub issuer_overlay_source_concepts: Vec<String>,
#[serde(skip, default)]
pub issuer_overlay_authoritative_concepts: Vec<String>,
}
#[derive(Debug, Deserialize, Clone)]
@@ -244,44 +282,114 @@ pub fn resolve_taxonomy_dir() -> Result<PathBuf> {
}
pub fn load_surface_pack(pack: FiscalPack) -> Result<SurfacePackFile> {
load_surface_pack_with_overlays(pack, None, None)
}
pub fn load_surface_pack_with_overlays(
pack: FiscalPack,
ticker: Option<&str>,
runtime_overlay: Option<&RuntimeIssuerOverlay>,
) -> Result<SurfacePackFile> {
let taxonomy_dir = resolve_taxonomy_dir()?;
let path = taxonomy_dir
.join("fiscal")
.join("v1")
.join(format!("{}.surface.json", pack.as_str()));
let mut file = load_surface_pack_file(&path)?;
let fiscal_dir = taxonomy_dir.join("fiscal").join("v1");
let mut file = SurfacePackFile {
version: "fiscal-v1".to_string(),
pack: pack.as_str().to_string(),
surfaces: Vec::new(),
};
merge_surface_pack_file(
&mut file,
load_surface_pack_file(&fiscal_dir.join(format!("{}.surface.json", pack.as_str())))?,
if matches!(pack, FiscalPack::Core) {
SurfaceOrigin::CorePrimary
} else {
SurfaceOrigin::PackPrimary
},
);
merge_optional_surface_pack_file(
&mut file,
load_optional_surface_pack_file(
&fiscal_dir.join(format!("{}.disclosure.surface.json", pack.as_str())),
)?,
if matches!(pack, FiscalPack::Core) {
SurfaceOrigin::CoreDisclosure
} else {
SurfaceOrigin::PackDisclosure
},
);
if !matches!(pack, FiscalPack::Core) {
let core_path = taxonomy_dir
.join("fiscal")
.join("v1")
.join("core.surface.json");
let core_file = load_surface_pack_file(&core_path)?;
let pack_inherited_keys = file
.surfaces
.iter()
.filter(|surface| surface.statement == "balance" || surface.statement == "cash_flow")
.map(|surface| (surface.statement.clone(), surface.surface_key.clone()))
.collect::<std::collections::HashSet<_>>();
file.surfaces.extend(
core_file
.surfaces
.into_iter()
.filter(|surface| {
surface.statement == "balance" || surface.statement == "cash_flow"
})
.filter(|surface| {
!pack_inherited_keys
.contains(&(surface.statement.clone(), surface.surface_key.clone()))
}),
merge_surface_pack_file(
&mut file,
load_surface_pack_file(&fiscal_dir.join("core.surface.json"))?,
SurfaceOrigin::CorePrimary,
);
}
merge_optional_surface_pack_file(
&mut file,
load_optional_surface_pack_file(&fiscal_dir.join("core.disclosure.surface.json"))?,
SurfaceOrigin::CoreDisclosure,
);
if let Some(normalized_ticker) = ticker
.map(|value| value.trim().to_ascii_lowercase())
.filter(|value| !value.is_empty())
{
merge_optional_surface_pack_file(
&mut file,
load_optional_surface_pack_file(
&fiscal_dir
.join("issuers")
.join(format!("{normalized_ticker}.surface.json")),
)?,
SurfaceOrigin::IssuerOverlay,
);
}
if let Some(runtime_overlay) = runtime_overlay {
merge_runtime_issuer_overlay(&mut file, runtime_overlay);
}
let _ = (&file.version, &file.pack);
Ok(file)
}
fn merge_runtime_issuer_overlay(target: &mut SurfacePackFile, overlay: &RuntimeIssuerOverlay) {
for mapping in &overlay.mappings {
let Some(existing) = target
.surfaces
.iter_mut()
.find(|candidate| candidate.surface_key == mapping.surface_key)
else {
continue;
};
if existing.statement != mapping.statement {
continue;
}
existing.issuer_overlay_source_concepts.extend(
mapping
.allowed_source_concepts
.iter()
.cloned()
.filter(|concept| !concept.trim().is_empty()),
);
existing.issuer_overlay_authoritative_concepts.extend(
mapping
.allowed_authoritative_concepts
.iter()
.cloned()
.filter(|concept| !concept.trim().is_empty()),
);
existing.issuer_overlay_source_concepts.sort();
existing.issuer_overlay_source_concepts.dedup();
existing.issuer_overlay_authoritative_concepts.sort();
existing.issuer_overlay_authoritative_concepts.dedup();
}
}
fn load_surface_pack_file(path: &PathBuf) -> Result<SurfacePackFile> {
let raw = fs::read_to_string(path).with_context(|| {
format!(
@@ -297,6 +405,128 @@ fn load_surface_pack_file(path: &PathBuf) -> Result<SurfacePackFile> {
})
}
fn load_optional_surface_pack_file(path: &PathBuf) -> Result<Option<SurfacePackFile>> {
if !path.exists() {
return Ok(None);
}
load_surface_pack_file(path).map(Some)
}
fn merge_optional_surface_pack_file(
target: &mut SurfacePackFile,
file: Option<SurfacePackFile>,
origin: SurfaceOrigin,
) {
if let Some(file) = file {
merge_surface_pack_file(target, file, origin);
}
}
fn merge_surface_pack_file(
target: &mut SurfacePackFile,
mut incoming: SurfacePackFile,
origin: SurfaceOrigin,
) {
for mut surface in incoming.surfaces.drain(..) {
surface.origin = origin;
if let Some(existing) = target
.surfaces
.iter_mut()
.find(|candidate| candidate.surface_key == surface.surface_key)
{
if surface.origin == SurfaceOrigin::IssuerOverlay {
merge_surface_definition(existing, surface);
} else if matches!(
existing.origin,
SurfaceOrigin::PackPrimary | SurfaceOrigin::PackDisclosure
) && matches!(
surface.origin,
SurfaceOrigin::CorePrimary | SurfaceOrigin::CoreDisclosure
) {
continue;
} else {
merge_surface_definition(existing, surface);
}
} else {
target.surfaces.push(surface);
}
}
}
fn merge_surface_definition(existing: &mut SurfaceDefinition, incoming: SurfaceDefinition) {
if incoming.origin == SurfaceOrigin::IssuerOverlay {
existing.issuer_overlay_source_concepts.extend(
incoming
.allowed_source_concepts
.iter()
.cloned()
.filter(|concept| !concept.trim().is_empty()),
);
existing.issuer_overlay_authoritative_concepts.extend(
incoming
.allowed_authoritative_concepts
.iter()
.cloned()
.filter(|concept| !concept.trim().is_empty()),
);
if existing.statement.is_empty() {
existing.statement = incoming.statement;
}
if existing.label.is_empty() {
existing.label = incoming.label;
}
if existing.category.is_empty() {
existing.category = incoming.category;
}
if existing.unit.is_empty() {
existing.unit = incoming.unit;
}
if existing.formula_fallback.is_none() {
existing.formula_fallback = incoming.formula_fallback;
}
if existing.sign_transform.is_none() {
existing.sign_transform = incoming.sign_transform;
}
existing.include_in_output = existing.include_in_output || incoming.include_in_output;
existing.materiality_policy = if existing.materiality_policy.is_empty() {
incoming.materiality_policy
} else {
existing.materiality_policy.clone()
};
existing.detail_grouping_policy = if existing.detail_grouping_policy.is_empty() {
incoming.detail_grouping_policy
} else {
existing.detail_grouping_policy.clone()
};
existing.rollup_policy = if existing.rollup_policy.is_empty() {
incoming.rollup_policy
} else {
existing.rollup_policy.clone()
};
return;
}
existing.allowed_source_concepts.extend(
incoming
.allowed_source_concepts
.into_iter()
.filter(|concept| !concept.trim().is_empty()),
);
existing.allowed_authoritative_concepts.extend(
incoming
.allowed_authoritative_concepts
.into_iter()
.filter(|concept| !concept.trim().is_empty()),
);
existing.allowed_source_concepts.sort();
existing.allowed_source_concepts.dedup();
existing.allowed_authoritative_concepts.sort();
existing.allowed_authoritative_concepts.dedup();
}
pub fn load_crosswalk(regime: &str) -> Result<Option<CrosswalkFile>> {
let file_name = match regime {
"us-gaap" => "us-gaap.json",

View File

@@ -535,19 +535,19 @@
"authoritative_concept_key": "us-gaap:FinanceLeaseRightOfUseAssetAmortization"
},
"us-gaap:DerivativeAssets": {
"surface_key": "derivative_disclosure",
"surface_key": "derivative_instruments_disclosure",
"authoritative_concept_key": "us-gaap:DerivativeAssets"
},
"us-gaap:DerivativeLiabilities": {
"surface_key": "derivative_disclosure",
"surface_key": "derivative_instruments_disclosure",
"authoritative_concept_key": "us-gaap:DerivativeLiabilities"
},
"us-gaap:DerivativeAssetsCurrent": {
"surface_key": "derivative_disclosure",
"surface_key": "derivative_instruments_disclosure",
"authoritative_concept_key": "us-gaap:DerivativeAssetsCurrent"
},
"us-gaap:DerivativeLiabilitiesCurrent": {
"surface_key": "derivative_disclosure",
"surface_key": "derivative_instruments_disclosure",
"authoritative_concept_key": "us-gaap:DerivativeLiabilitiesCurrent"
},
"us-gaap:IncreaseDecreaseInContractWithCustomerLiability": {

View File

@@ -0,0 +1,389 @@
{
"version": "fiscal-v1",
"pack": "core",
"surfaces": [
{
"surface_key": "income_tax_disclosure",
"statement": "disclosure",
"label": "Income Tax Disclosures",
"category": "tax",
"order": 100,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:CurrentIncomeTaxExpenseBenefit",
"us-gaap:DeferredIncomeTaxExpenseBenefit",
"us-gaap:CurrentFederalTaxExpenseBenefit",
"us-gaap:CurrentForeignTaxExpenseBenefit",
"us-gaap:CurrentStateAndLocalTaxExpenseBenefit",
"us-gaap:DeferredFederalIncomeTaxExpenseBenefit",
"us-gaap:DeferredForeignIncomeTaxExpenseBenefit",
"us-gaap:DeferredStateAndLocalIncomeTaxExpenseBenefit",
"us-gaap:EffectiveIncomeTaxRateContinuingOperations",
"us-gaap:EffectiveIncomeTaxRateReconciliationAtFederalStatutoryIncomeTaxRate",
"us-gaap:EffectiveIncomeTaxRateReconciliationDeductionsExcessTaxBenefitsStockBasedCompensation",
"us-gaap:EffectiveIncomeTaxRateReconciliationFdiiPercent",
"us-gaap:EffectiveIncomeTaxRateReconciliationForeignIncomeTaxRateDifferential",
"us-gaap:EffectiveIncomeTaxRateReconciliationIntangiblePropertyTransfers",
"us-gaap:EffectiveIncomeTaxRateReconciliationInterestIncomeExpense",
"us-gaap:EffectiveIncomeTaxRateReconciliationOtherAdjustments",
"us-gaap:EffectiveIncomeTaxRateReconciliationStateAndLocalIncomeTaxes",
"us-gaap:EffectiveIncomeTaxRateReconciliationTaxCreditsResearch",
"us-gaap:EmployeeServiceShareBasedCompensationTaxBenefitFromCompensationExpense",
"us-gaap:IncomeTaxesPaidNet",
"us-gaap:IncomeTaxExaminationYearUnderExamination",
"us-gaap:IncomeLossFromContinuingOperationsBeforeIncomeTaxesDomestic",
"us-gaap:IncomeLossFromContinuingOperationsBeforeIncomeTaxesForeign",
"us-gaap:UnrecognizedTaxBenefitsIncomeTaxPenaltiesAndInterestAccrued",
"us-gaap:UnrecognizedTaxBenefitsIncomeTaxPenaltiesAndInterestExpense"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "debt_disclosure",
"statement": "disclosure",
"label": "Debt Disclosures",
"category": "debt",
"order": 200,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:DebtInstrumentFaceAmount",
"us-gaap:DebtInstrumentFairValue",
"us-gaap:DebtInstrumentInterestRateEffectivePercentage",
"us-gaap:DebtInstrumentInterestRateStatedPercentage",
"us-gaap:DebtInstrumentUnamortizedDiscountPremiumAndDebtIssuanceCostsNet",
"us-gaap:ExtinguishmentOfDebtAmount",
"us-gaap:LongTermDebtFairValue",
"us-gaap:LongTermDebtMaturitiesRepaymentsOfPrincipalRemainderOfFiscalYear",
"us-gaap:LongTermDebtMaturitiesRepaymentsOfPrincipalInNextTwelveMonths",
"us-gaap:LongTermDebtMaturitiesRepaymentsOfPrincipalInYearTwo",
"us-gaap:LongTermDebtMaturitiesRepaymentsOfPrincipalInYearThree",
"us-gaap:LongTermDebtMaturitiesRepaymentsOfPrincipalInYearFour",
"us-gaap:LongTermDebtMaturitiesRepaymentsOfPrincipalInYearFive",
"us-gaap:LongTermDebtMaturitiesRepaymentsOfPrincipalAfterYearFive",
"us-gaap:PaymentsOfDebtRestructuringCosts",
"us-gaap:ProceedsFromDebtMaturingInMoreThanThreeMonths",
"us-gaap:ProceedsFromRepaymentsOfShortTermDebtMaturingInThreeMonthsOrLess",
"us-gaap:ProceedsFromShortTermDebtMaturingInThreeMonthsOrLess",
"us-gaap:RepaymentsOfShortTermDebtMaturingInThreeMonthsOrLess",
"us-gaap:ShortTermDebtWeightedAverageInterestRate"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "investment_securities_disclosure",
"statement": "disclosure",
"label": "Investment Securities Disclosures",
"category": "securities",
"order": 300,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:AvailableForSaleDebtSecuritiesAccumulatedGrossUnrealizedGainBeforeTax",
"us-gaap:AvailableForSaleDebtSecuritiesAccumulatedGrossUnrealizedLossBeforeTax",
"us-gaap:AvailableForSaleDebtSecuritiesAmortizedCostBasis",
"us-gaap:AvailableForSaleSecuritiesDebtMaturitiesNextRollingTwelveMonthsAmortizedCostBasis",
"us-gaap:AvailableForSaleSecuritiesDebtMaturitiesNextRollingTwelveMonthsFairValue",
"us-gaap:AvailableForSaleSecuritiesDebtMaturitiesRollingAfterYearTenAmortizedCostBasis",
"us-gaap:AvailableForSaleSecuritiesDebtMaturitiesRollingAfterYearTenFairValue",
"us-gaap:AvailableForSaleSecuritiesDebtMaturitiesRollingYearSixThroughTenAmortizedCostBasis",
"us-gaap:AvailableForSaleSecuritiesDebtMaturitiesRollingYearSixThroughTenFairValue",
"us-gaap:AvailableForSaleSecuritiesDebtMaturitiesRollingYearTwoThroughFiveAmortizedCostBasis",
"us-gaap:AvailableForSaleSecuritiesDebtMaturitiesRollingYearTwoThroughFiveFairValue",
"us-gaap:DebtSecuritiesAvailableForSaleContinuousUnrealizedLossPosition12MonthsOrLonger",
"us-gaap:DebtSecuritiesAvailableForSaleContinuousUnrealizedLossPosition12MonthsOrLongerAccumulatedLoss",
"us-gaap:DebtSecuritiesAvailableForSaleContinuousUnrealizedLossPositionLessThan12Months",
"us-gaap:DebtSecuritiesAvailableForSaleContinuousUnrealizedLossPositionLessThan12MonthsAccumulatedLoss",
"us-gaap:DebtSecuritiesAvailableForSaleRealizedGain",
"us-gaap:DebtSecuritiesAvailableForSaleRealizedLoss",
"us-gaap:DebtSecuritiesAvailableForSaleUnrealizedLossPosition",
"us-gaap:DebtSecuritiesAvailableForSaleUnrealizedLossPositionAccumulatedLoss"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "derivative_instruments_disclosure",
"statement": "disclosure",
"label": "Derivative Instruments Disclosures",
"category": "derivatives",
"order": 400,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:DerivativeAssets",
"us-gaap:DerivativeAssetsCurrent",
"us-gaap:DerivativeAssetsNoncurrent",
"us-gaap:DerivativeLiabilities",
"us-gaap:DerivativeLiabilitiesCurrent",
"us-gaap:DerivativeLiabilitiesNoncurrent",
"us-gaap:DerivativeFairValueOfDerivativeAsset",
"us-gaap:DerivativeFairValueOfDerivativeLiability",
"us-gaap:DerivativeAssetFairValueGrossAssetIncludingNotSubjectToMasterNettingArrangement",
"us-gaap:DerivativeAssetFairValueGrossLiability",
"us-gaap:DerivativeLiabilityFairValueGrossAsset",
"us-gaap:DerivativeLiabilityFairValueGrossLiabilityIncludingNotSubjectToMasterNettingArrangement"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "lease_disclosure",
"statement": "disclosure",
"label": "Lease Obligations Disclosures",
"category": "leases",
"order": 500,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:FinanceLeaseInterestPaymentOnLiability",
"us-gaap:FinanceLeaseLiabilityPaymentsDue",
"us-gaap:FinanceLeaseLiabilityPaymentsRemainderOfFiscalYear",
"us-gaap:FinanceLeaseLiabilityPaymentsDueNextTwelveMonths",
"us-gaap:FinanceLeaseLiabilityPaymentsDueYearTwo",
"us-gaap:FinanceLeaseLiabilityPaymentsDueYearThree",
"us-gaap:FinanceLeaseLiabilityPaymentsDueYearFour",
"us-gaap:FinanceLeaseLiabilityPaymentsDueYearFive",
"us-gaap:FinanceLeaseLiabilityPaymentsDueAfterYearFive",
"us-gaap:FinanceLeaseLiabilityUndiscountedExcessAmount",
"us-gaap:FinanceLeaseRightOfUseAssetAmortization",
"us-gaap:LesseeOperatingLeaseLiabilityPaymentsDue",
"us-gaap:LesseeOperatingLeaseLiabilityPaymentsRemainderOfFiscalYear",
"us-gaap:LesseeOperatingLeaseLiabilityPaymentsDueNextTwelveMonths",
"us-gaap:LesseeOperatingLeaseLiabilityPaymentsDueYearTwo",
"us-gaap:LesseeOperatingLeaseLiabilityPaymentsDueYearThree",
"us-gaap:LesseeOperatingLeaseLiabilityPaymentsDueYearFour",
"us-gaap:LesseeOperatingLeaseLiabilityPaymentsDueYearFive",
"us-gaap:LesseeOperatingLeaseLiabilityPaymentsDueAfterYearFive",
"us-gaap:LesseeOperatingLeaseLiabilityUndiscountedExcessAmount",
"us-gaap:RightOfUseAssetObtainedInExchangeForFinanceLeaseLiability",
"us-gaap:RightOfUseAssetObtainedInExchangeForOperatingLeaseLiability"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "intangible_assets_disclosure",
"statement": "disclosure",
"label": "Intangible Assets Disclosures",
"category": "intangibles",
"order": 600,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:AmortizationOfIntangibleAssets",
"us-gaap:FiniteLivedIntangibleAssetsAccumulatedAmortization",
"us-gaap:FiniteLivedIntangibleAssetsAmortizationExpenseRemainderOfFiscalYear",
"us-gaap:FiniteLivedIntangibleAssetsAmortizationExpenseNextTwelveMonths",
"us-gaap:FiniteLivedIntangibleAssetsAmortizationExpenseYearTwo",
"us-gaap:FiniteLivedIntangibleAssetsAmortizationExpenseYearThree",
"us-gaap:FiniteLivedIntangibleAssetsAmortizationExpenseYearFour",
"us-gaap:FiniteLivedIntangibleAssetsAmortizationExpenseYearFive",
"us-gaap:FiniteLivedIntangibleAssetsAmortizationExpenseAfterYearFive",
"us-gaap:FiniteLivedIntangibleAssetsGross",
"us-gaap:FinitelivedIntangibleAssetsAcquired1"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "business_combinations_disclosure",
"statement": "disclosure",
"label": "Business Combinations Disclosures",
"category": "ma",
"order": 700,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:BusinessAcquisitionsProFormaNetIncomeLoss",
"us-gaap:BusinessAcquisitionsProFormaRevenue",
"us-gaap:BusinessCombinationProFormaInformationRevenueOfAcquireeSinceAcquisitionDateActual"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "revenue_disclosure",
"statement": "disclosure",
"label": "Revenue Disclosures",
"category": "revenue",
"order": 800,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:RevenueRemainingPerformanceObligation",
"us-gaap:RevenueRemainingPerformanceObligationPercentage"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "cash_flow_disclosure",
"statement": "disclosure",
"label": "Cash Flow Disclosures",
"category": "cash_flow",
"order": 900,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalentsPeriodIncreaseDecreaseIncludingExchangeRateEffect"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "equity_investments_disclosure",
"statement": "disclosure",
"label": "Equity Investments Disclosures",
"category": "equity_investments",
"order": 1000,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:EquityMethodInvestmentOwnershipPercentage",
"us-gaap:EquityMethodInvestments",
"us-gaap:EquityMethodInvestmentsFunded",
"us-gaap:EquitySecuritiesFVNINoncurrent",
"us-gaap:EquitySecuritiesFvNiRealizedGainLoss",
"us-gaap:EquitySecuritiesFvNiUnrealizedGainLoss",
"us-gaap:EquitySecuritiesWithoutReadilyDeterminableFairValueAmount"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "share_based_compensation_disclosure",
"statement": "disclosure",
"label": "Share-Based Compensation Disclosures",
"category": "share_based_compensation",
"order": 1100,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:AdjustmentsToAdditionalPaidInCapitalSharebasedCompensationRequisiteServicePeriodRecognitionValue",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsForfeitedInPeriod",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsForfeituresWeightedAverageGrantDateFairValue",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsGrantsInPeriod",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsGrantsInPeriodWeightedAverageGrantDateFairValue",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsNonvestedNumber",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsNonvestedWeightedAverageGrantDateFairValue",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsVestedInPeriod",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsVestedInPeriodTotalFairValue",
"us-gaap:ShareBasedCompensationArrangementByShareBasedPaymentAwardEquityInstrumentsOtherThanOptionsVestedInPeriodWeightedAverageGrantDateFairValue"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "deferred_tax_balance_disclosure",
"statement": "disclosure",
"label": "Deferred Tax Balance Disclosures",
"category": "deferred_tax_balances",
"order": 1200,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:AccruedIncomeTaxesCurrent",
"us-gaap:AccruedIncomeTaxesNoncurrent",
"us-gaap:DeferredTaxAssetsDeferredIncome",
"us-gaap:DeferredTaxAssetsGross",
"us-gaap:DeferredTaxAssetsLiabilitiesNet",
"us-gaap:DeferredTaxAssetsOther",
"us-gaap:DeferredTaxAssetsTaxDeferredExpenseCompensationAndBenefitsShareBasedCompensationCost",
"us-gaap:DeferredTaxAssetsTaxDeferredExpenseReservesAndAccrualsOther",
"us-gaap:DeferredTaxAssetsValuationAllowance",
"us-gaap:DeferredTaxLiabilitiesLeasingArrangements",
"us-gaap:DeferredTaxLiabilitiesOther"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "contract_liability_disclosure",
"statement": "disclosure",
"label": "Contract Liability Disclosures",
"category": "contract_liabilities",
"order": 1300,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:ContractWithCustomerLiabilityIncurred",
"us-gaap:ContractWithCustomerLiabilityRevenueRecognized"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "acquisition_allocation_disclosure",
"statement": "disclosure",
"label": "Acquisition Allocation Disclosures",
"category": "acquisition_allocation",
"order": 1400,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:BusinessCombinationRecognizedIdentifiableAssetsAcquiredAndLiabilitiesAssumedCashAndEquivalents",
"us-gaap:BusinessCombinationRecognizedIdentifiableAssetsAcquiredAndLiabilitiesAssumedDeferredTaxLiabilities",
"us-gaap:BusinessCombinationRecognizedIdentifiableAssetsAcquiredAndLiabilitiesAssumedIntangibles",
"us-gaap:BusinessCombinationRecognizedIdentifiableAssetsAcquiredAndLiabilitiesAssumedNoncurrentLiabilitiesLongTermDebt",
"us-gaap:BusinessCombinationRecognizedIdentifiableAssetsAcquiredGoodwillAndLiabilitiesAssumedNet"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "other_comprehensive_income_disclosure",
"statement": "disclosure",
"label": "Other Comprehensive Income Disclosures",
"category": "oci",
"order": 1500,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:OtherComprehensiveIncomeLossAvailableForSaleSecuritiesAdjustmentNetOfTax",
"us-gaap:OtherComprehensiveIncomeLossBeforeReclassificationsTax",
"us-gaap:OtherComprehensiveIncomeLossCashFlowHedgeGainLossAfterReclassificationAndTax",
"us-gaap:OtherComprehensiveIncomeLossCashFlowHedgeGainLossBeforeReclassificationAfterTax",
"us-gaap:OtherComprehensiveIncomeLossCashFlowHedgeGainLossReclassificationBeforeTax",
"us-gaap:OtherComprehensiveIncomeLossForeignCurrencyTransactionAndTranslationAdjustmentNetOfTax",
"us-gaap:OtherComprehensiveIncomeLossNetOfTaxPortionAttributableToParent",
"us-gaap:OtherComprehensiveIncomeLossTaxPortionAttributableToParent1"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
}
]
}

View File

@@ -1538,31 +1538,6 @@
"materiality_policy": "cash_flow_default",
"include_in_output": false
},
{
"surface_key": "derivative_disclosure",
"statement": "balance",
"label": "Derivative Instruments Disclosure",
"category": "disclosure",
"order": 181,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"us-gaap:DerivativeAssets",
"us-gaap:DerivativeAssetsCurrent",
"us-gaap:DerivativeAssetsNoncurrent",
"us-gaap:DerivativeLiabilities",
"us-gaap:DerivativeLiabilitiesCurrent",
"us-gaap:DerivativeLiabilitiesNoncurrent",
"us-gaap:DerivativeFairValueOfDerivativeAsset",
"us-gaap:DerivativeFairValueOfDerivativeLiability",
"us-gaap:DerivativeAssetFairValueGrossAssetIncludingNotSubjectToMasterNettingArrangement",
"us-gaap:DerivativeLiabilityFairValueGrossLiabilityIncludingNotSubjectToMasterNettingArrangement"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "changes_other_noncurrent_liabilities",
"statement": "cash_flow",
@@ -1877,6 +1852,98 @@
"detail_grouping_policy": "top_level_only",
"materiality_policy": "cash_flow_default"
},
{
"surface_key": "common_stock_and_apic",
"statement": "equity",
"label": "Common Stock and APIC",
"category": "equity",
"order": 10,
"unit": "currency",
"rollup_policy": "direct_only",
"allowed_source_concepts": [
"us-gaap:CommonStocksIncludingAdditionalPaidInCapital"
],
"allowed_authoritative_concepts": [
"us-gaap:CommonStocksIncludingAdditionalPaidInCapital"
],
"formula_fallback": null,
"detail_grouping_policy": "top_level_only",
"materiality_policy": "balance_default"
},
{
"surface_key": "retained_earnings",
"statement": "equity",
"label": "Retained Earnings",
"category": "equity",
"order": 20,
"unit": "currency",
"rollup_policy": "direct_only",
"allowed_source_concepts": [
"us-gaap:RetainedEarningsAccumulatedDeficit"
],
"allowed_authoritative_concepts": [
"us-gaap:RetainedEarningsAccumulatedDeficit"
],
"formula_fallback": null,
"detail_grouping_policy": "top_level_only",
"materiality_policy": "balance_default"
},
{
"surface_key": "accumulated_other_comprehensive_income",
"statement": "equity",
"label": "Accumulated Other Comprehensive Income",
"category": "equity",
"order": 30,
"unit": "currency",
"rollup_policy": "direct_only",
"allowed_source_concepts": [
"us-gaap:AccumulatedOtherComprehensiveIncomeLossNetOfTax"
],
"allowed_authoritative_concepts": [
"us-gaap:AccumulatedOtherComprehensiveIncomeLossNetOfTax"
],
"formula_fallback": null,
"detail_grouping_policy": "top_level_only",
"materiality_policy": "balance_default"
},
{
"surface_key": "other_equity",
"statement": "equity",
"label": "Other Equity",
"category": "equity",
"order": 40,
"unit": "currency",
"rollup_policy": "direct_only",
"allowed_source_concepts": [
"us-gaap:StockholdersEquityOther"
],
"allowed_authoritative_concepts": [
"us-gaap:StockholdersEquityOther"
],
"formula_fallback": null,
"detail_grouping_policy": "top_level_only",
"materiality_policy": "balance_default"
},
{
"surface_key": "total_equity",
"statement": "equity",
"label": "Total Equity",
"category": "equity",
"order": 50,
"unit": "currency",
"rollup_policy": "direct_only",
"allowed_source_concepts": [
"us-gaap:StockholdersEquity",
"us-gaap:StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest"
],
"allowed_authoritative_concepts": [
"us-gaap:StockholdersEquity",
"us-gaap:StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest"
],
"formula_fallback": null,
"detail_grouping_policy": "top_level_only",
"materiality_policy": "balance_default"
},
{
"surface_key": "income_tax_disclosure",
"statement": "disclosure",

View File

@@ -0,0 +1,184 @@
{
"version": "fiscal-v1",
"pack": "msft",
"surfaces": [
{
"surface_key": "contract_liability_disclosure",
"statement": "disclosure",
"label": "Contract Liability Disclosures",
"category": "contract_liabilities",
"order": 1300,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:ContractWithCustomerLiabilityRevenueDeferred",
"msft:ContractWithCustomerLiabilityRevenueRecognizedIncludingAdditions"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "business_combinations_disclosure",
"statement": "disclosure",
"label": "Business Combinations Disclosures",
"category": "ma",
"order": 700,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:AcquisitionsNetOfCashAcquiredAndPurchasesOfIntangibleAndOtherAssets"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "debt_disclosure",
"statement": "disclosure",
"label": "Debt Disclosures",
"category": "debt",
"order": 200,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:DebtInstrumentIssuanceYear",
"msft:DebtInstrumentMaturityYear",
"msft:PremiumOnDebtExchange1",
"msft:LongTermDebtMaturitiesRepaymentsOfPrincipalAfterYearFour"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "investment_securities_disclosure",
"statement": "disclosure",
"label": "Investment Securities Disclosures",
"category": "securities",
"order": 300,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:ImpairmentOfEquityInvestments",
"msft:ProceedsFromInvestments"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "lease_disclosure",
"statement": "disclosure",
"label": "Lease Obligations Disclosures",
"category": "leases",
"order": 500,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:FinanceLeaseLiabilityPaymentsDueAfterYearFour",
"msft:LesseeOperatingLeaseLiabilityPaymentsDueAfterYearFour"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "intangible_assets_disclosure",
"statement": "disclosure",
"label": "Intangible Assets Disclosures",
"category": "intangibles",
"order": 600,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:FiniteLivedIntangibleAssetsAmortizationExpenseAfterYearFour"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "acquisition_allocation_disclosure",
"statement": "disclosure",
"label": "Acquisition Allocation Disclosures",
"category": "acquisition_allocation",
"order": 1400,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:BusinessCombinationRecognizedIdentifiableAssetsAcquiredAndLiabilitiesAssumedIncomeTaxLiabilitiesNoncurrent",
"msft:BusinessCombinationRecognizedIdentifiableAssetsAcquiredAndLiabilitiesAssumedOtherAssets",
"msft:BusinessCombinationRecognizedIdentifiableAssetsAcquiredAndLiabilitiesAssumedOtherLiabilities"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "equity_investments_disclosure",
"statement": "disclosure",
"label": "Equity Investments Disclosures",
"category": "equity_investments",
"order": 1000,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:EquityInterestPercentage",
"msft:EquityMethodInvestmentsTotalFundingCommitments"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "deferred_tax_balance_disclosure",
"statement": "disclosure",
"label": "Deferred Tax Balance Disclosures",
"category": "deferred_tax_balances",
"order": 1200,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:DeferredTaxAssetsAmortization",
"msft:DeferredTaxAssetsBookTaxBasisDifferencesInInvestmentsAndDebt",
"msft:DeferredTaxAssetsCapitalizedResearchAndDevelopment",
"msft:DeferredTaxAssetsLeasingLiabilities",
"msft:DeferredTaxAssetsOperatingLossAndTaxCreditCarryForwards",
"msft:DeferredTaxLiabilitiesBookTaxBasisDifferencesInvestmentsAndDebt",
"msft:DeferredTaxLiabilitiesDeferredTaxOnForeignEarnings",
"msft:DeferredTaxLiabilitiesDepreciation"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
},
{
"surface_key": "income_tax_disclosure",
"statement": "disclosure",
"label": "Income Tax Disclosures",
"category": "tax",
"order": 100,
"unit": "currency",
"rollup_policy": "aggregate_children",
"allowed_source_concepts": [
"msft:EffectiveIncomeTaxRateReconciliationDeductionsExcessTaxBenefitsStockBasedCompensation",
"msft:EffectiveIncomeTaxRateReconciliationInterestIncomeExpense",
"msft:EffectiveIncomeTaxRateReconciliationIntangiblePropertyTransfers"
],
"allowed_authoritative_concepts": [],
"formula_fallback": null,
"detail_grouping_policy": "group_all_children",
"materiality_policy": "disclosure"
}
]
}