The specification · Normative text

Fold mechanism inventory

Every decision point in chant core’s fold path with the requirement that covers it. Derived from a complete read of the four files below.

A decision point is anywhere the mechanism chooses between admitting and rejecting, between evaluation modes, or between representations. One row each. Rows are not lines of code; several rows can live in one function and one row can span several.

FileRead
packages/core/src/fold/subset.tscomplete
packages/core/src/fold/fold.tscomplete
packages/core/src/fold/foldable-helpers.tscomplete
packages/core/src/discovery/fold-import.tsmodule doc, session/context types, scan, resolution, revival, interpretation, trust, taint, instrumentation

The coverage column names the S-*/F-* rule that governs the row (grammar.md, evaluation.md, verdict.md, taint.md, observables.md, values.md, divergence.md, hosts.md), or GAP with a reason. It cites rules only.


L1. Statement scan (scanExports)

The gate that runs before any expression is classified. Disqualifies whole files.

#DecisionBehaviorCovers
L1.1admissible export shapesexport const X = new Type(...), export const X = <expr>, export const {a,b} = <expr>, export {a,b}, export {a,b} from "./m", export function f(){}S-Module, S-ExportResource … S-ExportTypeOnly (grammar.md)
L1.2export defaultdisqualifies the file in full; the declarator named default in data-hostS-Disqualify; S-ExportDefault (grammar.md)
L1.3export * fromdisqualifies; no enumerable element listS-Disqualify (grammar.md)
L1.4exported class, let/vardisqualifiesS-Disqualify (grammar.md)
L1.5destructured export with rest, nested, or defaulted elementdisqualifiesS-Disqualify (grammar.md)
L1.6export type {...} and isTypeOnly re-export elementsskipped, erased; not a disqualifierS-ExportTypeOnly (grammar.md)
L1.7rationale for per-module rather than per-declaration fallbackan unfoldable export can reference or be referenced by a foldable one in ways only running proves safeF-Total (verdict.md); S-Module rationale

L2. Expression shape classification (findSubsetViolation)

Shape only.

#DecisionBehaviorCovers
L2.1unwrappingparenthesized / as / satisfies / ! recurse into the inner expressionS-Unwrap
L2.2literalsstring, no-substitution template, numeric, true, false, null admittedS-Literal
L2.3bare identifieralways shape-valid; resolution is not this layer’s questionF-Div-Ident (divergence.md)
L2.4tagged template interioropaque; not recursed intoF-Div-Tag (divergence.md)
L2.5template expressionadmitted when every span isS-Template
L2.6object memberliteral key required; shorthand always valid; spread recursesS-Object / S-Prop / S-Shorthand / S-SpreadProp
L2.7element access keystring or numeric literal only, else EVL003S-Index
L2.8operatorsclosed sets SUPPORTED_BINARY_OPERATORS (13) and SUPPORTED_UNARY_OPERATORS (2)S-Unary, S-Binary; F-Eval-Unary, F-Eval-Binary
L2.9flow insensitivityevery branch of &&/||/??/?: must be shape-validF-Exc-Lazy (divergence.md)
L2.10newevery argument classified positionally, no props-position assumptionS-New
L2.11call; registered helpername-only check, provenance deferred; this is the expression classifier, and foldProject’s resolveCallExpression asks for a project binding firstF-Div-Provenance (divergence.md); F-Eval-CallLocal
L2.12call; intrinsic call formregistry-gated, registry is an optional parameterF-Exc-(divergence.md)
L2.13call; eager intrinsicregistry-gatedS-CallEager; F-Eval-CallEager
L2.14call; method (x.y())admitted unconditionally, receiver and args recursedS-CallMethod; F-Eval-CallMethod
L2.15call; <call>(...).stepadmitted unconditionally at the property-access nodeS-CompositeStep; F-Eval-Member step 2
L2.16any other callviolation, callExpressionMessageS-Reject; F-Eval-Reject
L2.17project-local call shapethe classifier rejected it while the build folded it until chant-v0.72.0 (chant#2435); 1.2 gives it S-CallLocalS-CallLocal (grammar.md)
L2.18a const alias of a package call at a declaratorresolveLiveValue follows a top-level const, through alias chains, to a call of any lexicon export or a member access on one, and resolves the call there; the same read nested inside an expression stays callExpressionMessage. 1.6 writes it into F-DeclaratorF-Declarator; F-Call; F-Count

L3. Expression reduction (fold)

#DecisionBehaviorCovers
L3.1arrow / function expression as a valuerejected; nothing can serialize a functionF-Eval-Function; F-Val-Callable
L3.2template expressionconcatenation, spans coerced by String(); since chant-v0.68.0 an attribute reference, intrinsic or helper envelope in a span is a located rejection (chant#2349)F-Eval-Template
L3.3object spreadObject.assign; later keys win, insertion order preservedF-Eval-Object
L3.4object spread of a non-objectrejectedF-Eval-Object; F-Div-SpreadType
L3.5array spread of a non-arrayrejectedF-Eval-Array; F-Div-SpreadType
L3.6identifier not in constsconsult externals; else unresolvedF-Eval-Ident
L3.7bare processpointed rejection naming build parametersF-Eval-Ident step 4
L3.8identifier bound to same-file newonly externals may answer, which F-Prebuild is what makes possible; a folder with no module graph cannot construct, so it rejects and the file falls back to runF-Eval-Ident step 1; F-Prebuild; F-Div-SameFileNew; F-Count
L3.9property access on a resource-bound const{__attrRef} keyed by the const’s nameF-Eval-Member step 1
L3.10property access on null/undefinedreturns undefined refused since chant-v0.63.0; a located rejection pointing at ?.; file falls back to run, where it throwsF-Eval-Member step 4; F-Div-Nullish
L3.11property access on a {__resource} envelope{__attrRef} when the object is a plain identifier; rejected otherwise (chant#1535; silent wrong output otherwise)F-Eval-Member step 5
L3.12-x, !xJS coercionF-Eval-Unary
L3.13&&, ||, ??lazily evaluated, JS truthinessF-Eval-Binary; F-Exc-Lazy
L3.14arithmetic and comparisonJS semantics via unchecked castsF-Eval-Binary
L3.15new ns.Type(...)rejected; a namespace-qualified constructor cannot be resolved through named importsF-Eval-New; F-Div-NsNew
L3.16envelope-producing branches inside a folded function bodynew, tagged template, helper call, intrinsic call and .step are all refused when functionBodyDepth > 0F-Eval-New/Tagged/CallHelper/CallIntrinsic/Member step 2 (depth > 0); F-Div-Depth
L3.17eager intrinsic referenced as a bare valuerejected; “call it instead”F-Eval-Ident step 3; F-Div-Eager
L3.18method call receiver is a symbolic enveloperejected; else toString would answer with the placeholder’s shapeF-Eval-CallMethod; F-Div-Method
L3.19method call, named property not a functionrejectedF-Eval-CallMethod; F-Div-Method
L3.20.step narrowingonly when the callee is not already a helper, intrinsic, FoldableFunction, or shadowed by a const (isUnclaimedBareCall)S-Unclaimed, F-Eval-Member step 2; F-Div-Step
L3.21optional chain on nullish (added chant-v0.63.0)?. on null/undefined yields a short-circuit sentinel that propagates through the rest of the chain; further ./[], !, ?.(); and becomes undefined at the chain’s end (continuesOptionalChain)F-Eval-Member steps 3–4
L3.22?.() method call on nullish (added chant-v0.63.0)short-circuits like L3.21; a plain .() on nullish refusesF-Eval-CallMethod
L3.23envelope in a plain template span (added chant-v0.68.0, completed v0.69.0)symbolicEnvelopeKind refuses all five kinds that can reach a span: __attrRef, __intrinsic, __helper, __resource, __compositeStep. __symbol is produced only inside an intrinsic interior, so it cannot appear hereF-Eval-Template; F-Div-TemplateEnvelope (divergence.md)

L4. Value domain

#DecisionBehaviorCovers
L4.1FoldedValue union9 casesF-Val-Domain
L4.2FoldedResource.argspositional; authoritative when the shape is not (props)/(props, attributes); props is a viewF-Val-Arity
L4.3undefined in the unionno stated ruleF-Val-Undefined
L4.4FoldableFunctioncallable, never a value; explicitly not a FoldedValueF-Val-Callable
L4.5carriesLiveObjectprototype other than Object/Array; and typeof === "function" counts as liveF-Val-Live

L5. Scope, resolution, and project-local calls

#DecisionBehaviorCovers
L5.1collectConststop-level const with an identifier name and an initializer, single fileF-Bind
L5.2externalspre-resolved imported bindings, and the instances F-Prebuild constructed for this file’s new-valued consts; consulted only when consts missesF-Eval-Ident; F-Prebuild
L5.3shadowingconsts before externals; a local const defeats a registered helper or intrinsic nameF-Eval-Ident; F-Eval-CallLocal step 4
L5.4project-local function admissibilityplain params, body is one expression or consts then a final return; no generator, async, rest param, early return, let/varS-FnBody; F-Eval-CallLocal step 1
L5.5body scopefolds in the defining module’s scope, parameters bound on topF-Eval-CallLocal step 4
L5.6parameter defaultsfolded in the callee’s scope when the argument is undefinedF-Eval-CallLocal step 4
L5.7block body with no returnevaluates to undefined, as running wouldF-Eval-CallLocal step 5
L5.8recursion boundMAX_FUNCTION_CALL_DEPTH = 32 on the expression path; a cross-file recursion ends at the engine’s stack, caught as a fallbackF-Eval-CallLocal step 2; F-Depth
L5.9leakedIdentitya call returning a live object the body produced records a taint edge; one merely passed through the arguments does notF-CallLeak; F-Eval-CallLocal step 6
L5.10error re-anchoringa failure inside a callee is re-thrown at the call site naming callee, file, position, reasonF-Eval-CallLocal step 7; F-Reason
L5.11params bare-specifier casethe one recognized bare import: @intentius/chant/params resolves against FoldSession.buildParamsF-Import (params)
L5.12hasObjectIdentitya captured value has identity when it is an object or a function; only those add to liveSourcesF-Import (verdict.md)
L5.13namespace import of a project fileresolves to a synthetic plain object of the target’s exportedValues; capture if any entry has identityF-Namespace (verdict.md)
L5.14namespace import of a packagenever resolved; the reason new ns.Type(...) is unreachableF-Namespace (verdict.md),
L5.15unresolved import never referenceddoes not force run; failure recorded for diagnostics onlyF-Reference (verdict.md)
L5.16same-file project-local functionsa top-level function declaration, exported or not, and a const bound to an arrow both fold when called; chant did this before the text said soS-LocalFunction; F-Bind

L6. Revival (reviveFoldedValue)

The second phase. Resolves envelope names through the folding file’s own imports.

#DecisionBehaviorCovers
L6.1live object passthroughAttrRef, Declarable, CompositeInstance, Intrinsic returned unchanged; the generic walk would destroy identity. The declarable marker is tested by identity: chant carries seven marker symbols, and a test for any own symbol admits an Intrinsic or a StackOutput as an entity (chant#2444). The reference’s broader test is safe only because its host has one marker kindF-Val-Live
L6.2{__symbol}resolved via SIMPLE_DOTTED_CHAIN regex, then real property accessF-Val-Fate, F-Val-Symbol-Scope
L6.3{__intrinsic}revived; real function resolved and invoked, both tag and call formF-Val-Fate
L6.4{__helper}revivedF-Val-Fate
L6.5{__compositeStep}revived, then .step read off the real resultF-Val-Fate
L6.6{__resource}revived into a real instance by the class the file’s import namesF-Val-Fate, F-Val-Arity
L6.7{__attrRef}passes through unrevived; the serializer walker accepts the envelopeF-Val-Fate
L6.8requireLiveRefsinside an intrinsic’s or helper’s arguments a {__attrRef} is rejected, because the receiver does instanceof checks and WeakRef derefs; elsewhere it passesF-Val-Position
L6.9composite-step argsrevived with requireLiveRefs: false; a composite stores props rather than inspecting themF-Val-Position

L7. Interpretation (the third evaluation mode)

Neither folding nor revival: the factory body is evaluated and the defining module is never imported.

#DecisionBehaviorCovers
L7.1rule 1; project files onlytext check on the specifier; a lexicon-published composite is deliberately never interpretedF-Call step 4; F-Host-Composite
L7.2rule 2; export const N = Composite(<fn>, "N")and Composite must be chant’s own in the defining moduleF-Host-Composite
L7.3rule 3; at most one parameter, bound plainlyno rest, default, nested, or array patternS-FactoryBody
L7.4rule 4; body shapeconcise expression, or consts then a final return; empty body rejected; must end in return (unlike L5.7)S-FactoryBody
L7.5rule 5; every expression in the subsetextended with new in value position and calls through a bare identifierS-FactoryBody
L7.6module-level resource reference declinesthat resource is a singleton the run path shares; interpretation would notF-Call step 4 (declines: module-level resource)
L7.7constResolvesToResource follows alias chainsconst a = new T(); const b = a; cannot smuggle one inF-Call step 4 (alias chains)
L7.8MAX_INTERPRETATION_DEPTH (16)exhaustion throws a propagated depth error naming the bound; the file falls back to run (chant-v0.68.0, chant#2370; before that it degraded to invocation and still reported fold)F-Depth

L8. File decision, session, and taint

#DecisionBehaviorCovers
L8.1FoldFileResultok with entities/exportedValues/liveSources, or a reasonF-Total, F-Reason
L8.2all-or-nothing per fileone unrecognized export disqualifies everythingF-Total
L8.3foldModule vs tryFoldFilefoldModule is per-export with an ok/false entry each and silently skips non-new exports; tryFoldFile is per-fileF-Total (per-file normative)
L8.4exportedValues completenessthe file’s whole export namespace, equal to what importing would giveF-Total
L8.5liveSourcesnon-primitive captures only; a primitive has no identity to disagree aboutF-Capture
L8.6forward taintimporter of a non-folding file is taintedF-Succ forward
L8.7reverse tainta file whose objects were captured taints the capturing fileF-Succ backward
L8.8fixpointseed with non-folding files, walk both edge sets to closureF-Taint, F-Fix
L8.9cycle detectionFoldSession.stack, located error naming the cycleF-Cycle
L8.10MAX_RESOLUTION_DEPTHa second bound, separate from L5.8 and L7.8F-Depth
L8.11per-file fold memoa file imported by many is folded exactly once; every referrer shares the resultF-Memo
L8.12per-initializer-node memoa composite call reached through several member accesses is invoked exactly once, “matching what actually running the file would do”F-Count
L8.13zero declarators after the gaterun("no foldable resource exports"); a file must export somethingF-NoExports (verdict.md)
L8.14file inside chant’s own module treerun; not project sourceF-NotProject (verdict.md)
L8.15composite-call result typemust be a CompositeInstance or Declarable, else runF-Call step 7 (verdict.md)
L8.16destructure sourcemust be a composite instance or indexable objectF-Declarator (verdict.md)
L8.17a re-export is a captureexport { a } from "./g" adds g to liveSources when the value has identityF-Declarator (verdict.md)
L8.19applyResolvedValuesets the export to whatever the invoked factory returned, unconditionally; the isDeclarable || isCompositeInstance test after it only tallies entities for the fold line. There is no step-7 refusal in chant, which 1.6 wrote into F-CallF-Call step 7
L8.18same-file construction pre-passevery top-level new-valued const constructed once, in source order, before any declarator; the exported-declarator loop reuses the instance rather than constructing a second one (preresolveResourceConsts, chant#1169)F-Prebuild; F-Count

L9. Trust and isolation

#DecisionBehaviorCovers
L9.1trust arm 1an active lexicon package of this build, matched by text against a closed set built from names the build resolvedF-Host-Trust arm 1
L9.2trust arm 1, subpathpackage root extracted from text and matched against the same setF-Host-Trust arm 1 (subpath)
L9.3trust arm 2specifier resolved, path checked against chant-core’s own tree; text is explicitly not enoughF-Host-Trust arm 2
L9.4no lexicon list suppliedarm 1 disabled entirely rather than loosenedF-Host-Trust (no package list)
L9.5sandboxed refusala fold needing an untrusted import is demoted to run; not an errorF-IsolatedRefusal
L9.6bare-specifier resolution cache is process-widedocumented as unsound for nested node_modules with a version override; the same assumption bundlers makeF-Host-Trust (stated assumption)

L10. Observables and side outputs

#DecisionBehaviorCovers
L10.1FoldExecutionCountsfactoryInvocations, projectFactoryInvocations, factoryInterpretations; process-wide, monotonic, resettableF-Obs-Counters
L10.2provenancesetPathProvenance records which composite parameter produced which emitted field, first (innermost) writer winsF-Obs-Provenance
L10.3per-file decision line[fold:fold] / [fold:run] <reason>, summarized without --verboseF-Obs-Report
L10.4FoldErrorlocated, carries an EVL rule id, constructed with stackTraceLimit = 0F-Reason
L10.5one wording per rejection kindshared message builders so two sites cannot driftF-Obs-Messages

L11. Rules over values

#DecisionBehaviorCovers
L11.1PostSynthContext.entitiesevery declared entity by name, the folded namespace after J3F-Rule-Input (rules.md)
L11.2PostSynthContext.outputsthe serialized output per lexicon, textF-Rule-Input (rules.md)
L11.3PostSynthContext.docsthe outputs parsed once per build, cached (chant#975)F-Rule-Input (rules.md)
L11.4PostSynthContext.envthe environment or stack name, so a policy may branch on itF-Rule-Input (rules.md)
L11.5PostSynthDiagnosticcheckId, severity, message, an artifact-side entity or a missing-resource marker (chant#2113), never a source lineF-Rule-Finding (rules.md)
L11.6severity configurationlint.config overrides a check’s own severityF-Rule-Finding (rules.md)
L11.7project policies under --sandboxloadPolicyChecks refuses in-process while the sandbox is armed; checks run in the child (chant#1131)F-Rule-Pure; F-Rule-Supply (rules.md)
L11.8rule registrylexicon checks and project policies keyed by id; a duplicate id is a registry errorF-Rule-Supply (rules.md)

L12. Generators

#DecisionBehaviorCovers
L12.1TypeScriptGenerator.generate(ir)one generator interface behind chant import, --from live import and carve-out (import/generator.ts, cli/commands/import.ts, import-live.ts, carve-emit.ts); a lexicon supplies the generatorF-Val-Source
L12.2export const <id> = new <Class>({…})the k8s generator’s form per resource: the logical id is the binding, the class is resolved from the kind, nested property entities are constructors (K8sGenerator.generate, emitProps)F-Val-Source
L12.3emitLiteralscalars, arrays and objects emitted as literals; a key that is not an identifier is quotedF-Val-Source
L12.4k8s round-trip suiteroundtrip.test.ts parses YAML and generates; scripts/full-roundtrip.sh re-serializes and compares resource count and kinds, not bytes, over kubernetes/examples at a 95% pass thresholdF-Val-Source

Coverage summary

The rule for the column. A row is covered only when a specific rule (S-Template, F-Eval-Member step 4, F-Val-Fate) governs what the row does. A citation of a whole file or judgment is not coverage. A partially covered row is GAP. There is no double counting, and the coverage gate checks that every cited identifier is defined in a spec file.

RowsCoveredGAP
L1 statement scan770
L2 shape classification18180
L3 expression reduction23230
L4 value domain550
L5 scope and local calls16160
L6 revival990
L7 interpretation880
L8 file decision and taint19190
L9 trust and isolation660
L10 observables550
L11 rules over values880
L12 generators440
total1281280

Row identifiers are stable and append-only. L3.10 names one decision point forever; a new row in a layer takes the next number and nothing is ever renumbered. A row that turns out to be wrong is struck through with a note, not removed, so a citation of it stays resolvable. Row identifiers are as stable as rule identifiers and for the same reason: the coverage gate cites them.

What this inventory does not cover

fold-import.ts was read for decision points. The No known unread region remains at the decision-point level.