examples/include-defaults/ is three files: base.fson (shared defaults), secrets.fson (a subtree to bind), and service.fson (the host that pulls both in).
base.fson
// Shared defaults, included by service files via %include.
{
timeout: 30,
retries: 3,
logging: {
level: "info",
format: "text"
}
}
secrets.fson
// Bound under "vault" by the alias %include in service.fson.
{
token: "s3cr3t",
region: "eu-west"
}
service.fson
{
%include "base.fson", // merge base's members as defaults
%include "secrets.fson" as vault, // bind secrets' root under "vault"
timeout: 60, // host wins over base's 30
service: "auth",
logging: { level: "debug" } // shallow: wholly shadows base logging
// --%include "extra.fson" disabled directive: kept, not resolved
}
The resolved view
auto r = Fson::load( "include-defaults/service.fson" );
auto& d = *r.document;
d.getInteger( "timeout", 0 ); // 60 — host wins
d.getInteger( "retries", 0 ); // 3 — from base.fson (default)
d.getString ( "service", "" ); // "auth"
d.getString ( "logging.level", "" ); // "debug"
d.getString ( "logging.format", "" ); // "" — shallow merge: host's `logging`
// wholly shadows base's, so
// `format` is gone
d.getString ( "vault.token", "" ); // "s3cr3t" — alias form
d.getString ( "vault.region", "" ); // "eu-west"
The shallow merge is the one that surprises people: because service.fson defines its own logging object, base's logging is replaced, not deep-merged — logging.format does not survive. See Include directives.
Provenance — where did each value come from?
d.isLocal( "timeout" ); // true — defined in service.fson
d.isLocal( "retries" ); // false — merged from base.fson
auto p = d.provenanceOf( "retries" );
// p->sourceFile → …/include-defaults/base.fson
// p->localPath → "retries"
auto v = d.provenanceOf( "vault.token" );
// v->sourceFile → …/include-defaults/secrets.fson
// v->localPath → "token" (NOT "vault.token" — the alias key is host-side only)
Saving
d.setPath( "retries", std::make_unique<Number>( 5LL ) );
Fson::save( d, "include-defaults/service.fson" );
retries did not exist in service.fson before — setPath promotes it to a host member. base.fson is never written. The two %include lines are reproduced verbatim; the disabled --%include comment stays as written.
The dependency set
for( auto const& f : r.dependencySet ) std::cout << f << '\n';
// …/include-defaults/base.fson
// …/include-defaults/secrets.fson
// …/include-defaults/service.fson ← host is included
This is the watch list for reload.

