@c4a/context 0.6.19 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +2 -2
  3. package/codeIndexPlan.d.ts +34 -0
  4. package/docs/README.md +7 -0
  5. package/docs/README.zh-CN.md +5 -0
  6. package/docs/getting-started.md +30 -24
  7. package/docs/guides/agent-guide.md +41 -46
  8. package/docs/guides/code-indexer-skill-authoring.md +124 -0
  9. package/docs/guides/indexer-provider-and-customization.md +140 -0
  10. package/docs/guides/markdown-indexer-skill-authoring.md +118 -0
  11. package/docs/reference/code-extractors.md +9 -24
  12. package/docs/reference/indexer-provider-protocol.md +808 -0
  13. package/docs/reference/project-api.md +41 -40
  14. package/index.d.ts +47 -1
  15. package/index.js +28010 -3945
  16. package/indexerAgentStepProtocol.d.ts +9391 -0
  17. package/indexerArtifactDependencies.d.ts +689 -0
  18. package/indexerArtifactPolicy.d.ts +335 -0
  19. package/indexerArtifactResult.d.ts +2009 -0
  20. package/indexerAuditFacts.d.ts +66 -0
  21. package/indexerAuditOverrideReadiness.d.ts +27 -0
  22. package/indexerAuditProtocol.d.ts +238 -0
  23. package/indexerAuditRevision.d.ts +726 -0
  24. package/indexerAuditRevisionActions.d.ts +236 -0
  25. package/indexerAuthoringFixture.d.ts +152 -0
  26. package/indexerBaseQuestionAmendment.d.ts +2403 -0
  27. package/indexerBenchmark.d.ts +1062 -0
  28. package/indexerCandidateCompile.d.ts +985 -0
  29. package/indexerCapabilityGroupEvidence.d.ts +129 -0
  30. package/indexerCatalogFallback.d.ts +1262 -0
  31. package/indexerCollectionMapping.d.ts +75 -0
  32. package/indexerContentLayers.d.ts +137 -0
  33. package/indexerContractOverlay.d.ts +879 -0
  34. package/indexerControlledInvocation.d.ts +512 -0
  35. package/indexerControlledProgram.d.ts +12535 -0
  36. package/indexerCoreExports.d.ts +21 -0
  37. package/indexerCustomizationDraft.d.ts +13800 -0
  38. package/indexerCustomizationLadder.d.ts +103 -0
  39. package/indexerDependencyView.d.ts +1610 -0
  40. package/indexerEvidenceAdapterResult.d.ts +504 -0
  41. package/indexerExampleDecision.d.ts +1606 -0
  42. package/indexerExampleIdentity.d.ts +132 -0
  43. package/indexerExampleIdentityAudit.d.ts +70 -0
  44. package/indexerExampleLinkageAudit.d.ts +80 -0
  45. package/indexerGeneratedAuthoringAudit.d.ts +208 -0
  46. package/indexerIncrementalImpact.d.ts +221 -0
  47. package/indexerInventoryDisposition.d.ts +443 -0
  48. package/indexerLayerComposition.d.ts +1652 -0
  49. package/indexerLayoutChange.d.ts +329 -0
  50. package/indexerLayoutProposalSet.d.ts +447 -0
  51. package/indexerLayoutResolver.d.ts +342 -0
  52. package/indexerLayoutTransition.d.ts +247 -0
  53. package/indexerLifecycle.d.ts +53 -0
  54. package/indexerMainLifecycle.d.ts +258 -0
  55. package/indexerMainRunLedger.d.ts +888 -0
  56. package/indexerMainRunProtocol.d.ts +6471 -0
  57. package/indexerMainWorkset.d.ts +2141 -0
  58. package/indexerMaterialAnswer.d.ts +738 -0
  59. package/indexerMaterialAnswerActualization.d.ts +91 -0
  60. package/indexerMaterialAnswerExecutionPlan.d.ts +2887 -0
  61. package/indexerMaterialAnswerFlow.d.ts +63 -0
  62. package/indexerMaterialAnswerLayout.d.ts +76 -0
  63. package/indexerMaterialAnswerReview.d.ts +217 -0
  64. package/indexerMaterialAnswerReviewRoute.d.ts +6145 -0
  65. package/indexerMaterialAnswerRunLedger.d.ts +918 -0
  66. package/indexerMaterialAnswerRunProtocol.d.ts +1253 -0
  67. package/indexerMaterialGapLedger.d.ts +3111 -0
  68. package/indexerMaterialQuestionExclusion.d.ts +129 -0
  69. package/indexerMaterialQuestionWorkset.d.ts +508 -0
  70. package/indexerNavigationArtifactGraph.d.ts +5 -0
  71. package/indexerNavigationArtifactPlan.d.ts +39 -0
  72. package/indexerOverlayQuestionAmendment.d.ts +2551 -0
  73. package/indexerOverlayQuestionApplyProposal.d.ts +4697 -0
  74. package/indexerParserCoordinate.d.ts +222 -0
  75. package/indexerParserFactView.d.ts +503 -0
  76. package/indexerPartitionConvergence.d.ts +496 -0
  77. package/indexerPartitionPlan.d.ts +919 -0
  78. package/indexerPartitionStrategyResolution.d.ts +594 -0
  79. package/indexerPhysicalArtifactAudit.d.ts +247 -0
  80. package/indexerPhysicalArtifactManifest.d.ts +449 -0
  81. package/indexerPlannedMaterialAnswer.d.ts +116 -0
  82. package/indexerPostAuthorComposition.d.ts +2000 -0
  83. package/indexerPostAuthorRunLedger.d.ts +1972 -0
  84. package/indexerPrimaryProjection.d.ts +262 -0
  85. package/indexerProfileContract.d.ts +3034 -0
  86. package/indexerProfileMetricAudit.d.ts +218 -0
  87. package/indexerProgramExecutionAuthorization.d.ts +227 -0
  88. package/indexerProgramRunProtocol.d.ts +7642 -0
  89. package/indexerProjectProposal.d.ts +2807 -0
  90. package/indexerProjectedArtifactFanOutAudit.d.ts +159 -0
  91. package/indexerProjectedArtifactPlan.d.ts +217 -0
  92. package/indexerProtocolCommon.d.ts +29 -0
  93. package/indexerProvider.d.ts +2510 -0
  94. package/indexerProviderComposition.d.ts +1357 -0
  95. package/indexerProviderContractReferences.d.ts +13 -0
  96. package/indexerProviderProfileResolution.d.ts +20 -0
  97. package/indexerProviderResolution.d.ts +752 -0
  98. package/indexerProviderResolutionAction.d.ts +678 -0
  99. package/indexerProviderRouting.d.ts +3909 -0
  100. package/indexerProviderSelectionProposal.d.ts +3311 -0
  101. package/indexerQuestionAuthority.d.ts +419 -0
  102. package/indexerReaderTargetInventory.d.ts +161 -0
  103. package/indexerReferenceOnlyAudit.d.ts +90 -0
  104. package/indexerRegistry.d.ts +3019 -0
  105. package/indexerRequirementComparison.d.ts +44 -0
  106. package/indexerRequirementConfirmation.d.ts +1193 -0
  107. package/indexerRequirementLifecycle.d.ts +3314 -0
  108. package/indexerRestrictedSelector.d.ts +63 -0
  109. package/indexerResultReconciliation.d.ts +6844 -0
  110. package/indexerResultReconciliationRun.d.ts +15 -0
  111. package/indexerRunEnvelope.d.ts +384 -0
  112. package/indexerRunProtocolCommon.d.ts +21 -0
  113. package/indexerSharedArtifactFingerprint.d.ts +33 -0
  114. package/indexerStructuredDeclaration.d.ts +513 -0
  115. package/indexerSubjectCatalog.d.ts +230 -0
  116. package/indexerSubjectIdentity.d.ts +19 -0
  117. package/indexerSubjectKeyAuthority.d.ts +785 -0
  118. package/indexerTemplateRendering.d.ts +485 -0
  119. package/indexerToolSnapshot.d.ts +431 -0
  120. package/indexerWorksetRead.d.ts +287 -0
  121. package/package.json +1 -1
  122. package/phases.d.ts +1 -1
@@ -0,0 +1,808 @@
1
+ # Indexer Provider protocol
2
+
3
+ Context defines one Provider manifest, `context-indexer.yaml`, with protocol
4
+ `context.indexer.provider/v1`. Code and Markdown Providers use the same field
5
+ tree; `domains`, profiles and declared operations describe their applicable
6
+ inputs.
7
+
8
+ This page documents the protocol surface currently exposed by `@c4a/context`.
9
+ It does not imply that the 0.7.0 CLI Route or its release channel is complete.
10
+
11
+ ## Resources and execution
12
+
13
+ A Provider may contain a controlled program, profile-bound instructions,
14
+ templates, an activation detector and an authoring inspector. Executable
15
+ resources use only:
16
+
17
+ ```yaml
18
+ execution:
19
+ runtime: node
20
+ entry: scripts/index.mjs
21
+ args: [--format=json]
22
+ ```
23
+
24
+ `entry` is a portable path inside the verified Bundle. `args` are literal
25
+ arguments. A free-form command, shell expression, environment interpolation,
26
+ absolute path or parent traversal is invalid.
27
+
28
+ The CLI never launches an executable from a discovered Skill installation
29
+ directory. A Host or the CLI first resolves an exact Provider envelope, verifies
30
+ the complete file ledger, and copies it to a content-addressed runtime stage.
31
+ The controlled launch then revalidates that stage and resolves the declared
32
+ entry there with `shell: false` and an empty inherited environment.
33
+
34
+ Allowlisted first-party and verified Bundle programs may enter the trusted
35
+ path directly. Every other Provider program, and every project-local program
36
+ even when it extends an allowlisted Provider, requires an exact
37
+ `context.indexer.program-authorization/v1` receipt from the independent
38
+ program-execution authority. The receipt binds the project, Provider
39
+ fingerprint and manifest, program origin/path/content digest, structured
40
+ execution, requested capabilities, fixed dependencies, source scope, limits
41
+ and policy digest. A local program is restricted to
42
+ `src/indexer/<indexer-id>/index.ts`; the CLI reads a regular non-symlink file
43
+ from the workspace before producing its report.
44
+
45
+ The controlled invocation rechecks the complete receipt and program identity.
46
+ Changing local bytes, the Provider Bundle, entry or arguments, capabilities,
47
+ dependencies, scope or limits invalidates the authorization. An ordinary
48
+ managed authority cannot issue this receipt, and the receipt always records
49
+ `sandboxed_program: false`: it authorizes trusted execution but does not claim
50
+ malicious-code isolation.
51
+
52
+ Optional external reads are declared separately under
53
+ `provides.tool_sources[]`. Each declaration contains only a stable id, a
54
+ versioned Host handler and request protocol, the fixed
55
+ `context.indexer.tool-snapshot/v1` output protocol, a closed operation list and
56
+ `optional: true`. It cannot contain an executable path or command. The
57
+ declaration is copied into the Agent-visible Skill capability and the final
58
+ Provider composition plan with its owning Provider layer; it does not grant
59
+ execution authority. The Host validates and executes its own installed adapter,
60
+ while Context validates the resulting tool snapshot and keeps the local parser
61
+ baseline independent from optional tool availability.
62
+
63
+ ## Two-stage selection validation
64
+
65
+ `validateIndexerSelectionStatic` accepts only the proposed registry. It closes
66
+ requirement ownership, read scope, profile composition, portable distribution,
67
+ exact Provider identity/version/integrity and the data shape of stable config.
68
+ Its output is a canonical list of Provider resolution requests. This phase does
69
+ not resolve, read, stage or execute a Provider resource.
70
+
71
+ After the resolver returns and the CLI creates a content-addressed stage,
72
+ `validateIndexerSelectionFinal` consumes the exact static report. It rechecks
73
+ the resolved envelope and actual staged file ledger, loads the sole Provider
74
+ manifest, verifies profile/operation/composer/extension bindings, validates
75
+ config against the Bundle's closed data-only schema, binds the project-local
76
+ customization fingerprint and requires a policy digest for executable
77
+ resources. Missing, duplicate, stale or extra inputs fail closed.
78
+
79
+ The final stable report excludes transport paths, delivery timestamps and
80
+ runtime receipt digests. Those values remain in a separate runtime receipt
81
+ projection, so rematerializing identical content does not make the selection
82
+ stale. The workflow Route must use the static report as the hard predecessor of
83
+ resolution; the protocol functions alone do not authorize Host materialization.
84
+
85
+ The only default persistent selection authority is `src/indexers.yaml`.
86
+ Distribution locators are portable identities such as `cli-bundled://`,
87
+ `plugin://`, `workspace://`, `package://` or `marketplace://`; a discovered
88
+ Skill installation path and a runtime transport/stage path never enter the
89
+ registry or stable report. The workspace persistence audit rejects the legacy
90
+ `package.json.context.codeIndex.extensions` field. Provider-only projects also
91
+ cannot persist a `src/indexer/` directory; declared local customization is
92
+ limited to the fixed project-relative resource set.
93
+
94
+ Minimal local customization runs as a resumable subloop. An Agent draft must
95
+ consume a final CLI capability-gap proof. The CLI validates and
96
+ content-address stages the draft, then project preparation revalidates the
97
+ target selection and exact staged Providers before creating a CAS-bound
98
+ proposal. Project-local programs stop for independent execution authorization;
99
+ dependency authorization creates a new locked successor proposal instead of a
100
+ detached result. After the single transactional apply, the CLI records a
101
+ durable apply observation, verifies every target digest, reruns finalized
102
+ selection validation, and returns the applied registry for one final static
103
+ selection audit.
104
+
105
+ ## Skill capability and Provider composition
106
+
107
+ Context normalizes every verified manifest to
108
+ `context.indexer.skill-capability/v1`. This Agent-visible view contains the
109
+ Skill's profiles, operations, accepted extension fragments, source roles,
110
+ logical units, composers, program capabilities and supported customization
111
+ steps. It is canonical and content-digested; it does not expose a discovered
112
+ installation path or grant execution authority.
113
+
114
+ Final selection builds one
115
+ `context.indexer.provider-composition-plan/v1` for each Indexer owner. The plan
116
+ binds every active profile to its exact Provider layer, keeps one primary
117
+ authority for each enabled operation, admits only declared pre-authority
118
+ fragments, merges identical source-role and logical-unit capabilities, and
119
+ rejects conflicting logical-unit definitions. Provider instruction resources
120
+ remain independently attributed instead of being concatenated implicitly,
121
+ layer configs remain separately digested, and an exact project template
122
+ override replaces only its matching template id/profile. Input array order is
123
+ not authority: all projections use canonical identity sorting.
124
+
125
+ The complete composition plans are part of the stable final selection report,
126
+ so downstream workset and authoring steps consume a validated composition
127
+ rather than rediscovering Provider precedence.
128
+
129
+ ## Partition strategy authority
130
+
131
+ A Provider may declare profile-bound partition strategies under
132
+ `provides.partition_strategies[]` with a stable id and non-negative priority.
133
+ The manifest does not provide its own authority digest. Context derives the
134
+ implementation identity from the verified Bundle and manifest; a validated
135
+ local customization uses its exact file digest, while a CLI builtin is bound to
136
+ the current CLI release digest.
137
+
138
+ `context.indexer.partition-strategy-resolution/v1` binds the Indexer and
139
+ registry fingerprints, selected profiles, Provider integrity, optional local
140
+ customization and every strategy authority. A local declaration with the same
141
+ id replaces only that Provider strategy. All effective project strategies are
142
+ ordered by declared priority and id before any CLI builtin. A CLI builtin
143
+ cannot shadow a project strategy, and an undeclared profile or ambiguous
144
+ per-profile priority fails validation. The order-sensitive strategy-set digest
145
+ is copied into the partition workset, so reordering or changing any authority
146
+ makes prior work stale.
147
+
148
+ ## Source roles and Artifact policy
149
+
150
+ A Provider may declare source-role and logical-unit identifiers, but the
151
+ selected CLI profile contract owns Artifact kinds, metrics, thresholds and
152
+ policy variants. Final selection rejects `quality_guidance.metric_ids`,
153
+ `logical_units[].artifacts.recommended` kinds and
154
+ `supported_policy_variants` that are not registered by the selected base
155
+ profile. A namespaced extension inherits this check from its declared base
156
+ profile. The strict manifest schema has no numeric limit or threshold field.
157
+
158
+ Before authoring a logical unit, the CLI evaluates each selected policy
159
+ variant's restricted eligibility selector over an allowlisted canonical-fact
160
+ projection. The resulting
161
+ `context.indexer.artifact-policy-eligibility/v1` binds the profile and operator
162
+ contracts, canonical facts, Provider-supported variant set, eligible Artifact
163
+ kinds and derived thresholds. `inflation-sensitive` maximums use the fixed CLI
164
+ rule; the Provider cannot return a threshold or self-report a pass.
165
+
166
+ An author Result declares one validated source role and, when it emits
167
+ Artifacts, one `context.indexer.artifact-bundle/v1` for its logical unit. The
168
+ Bundle chooses exactly one eligible variant and classifies each Artifact as
169
+ required, discretionary or a semantic split. The CLI requires exact agreement
170
+ between the Bundle and Result payload, registered required/discretionary kinds,
171
+ known evidence, authorized reader questions and the derived discretionary
172
+ fan-out limit. Semantic split parts retain `split_of`, the parent's kind and a
173
+ non-overlapping stable boundary. An empty Result has no Bundle; a non-empty
174
+ Result cannot omit it. There is no global hard limit on total valid logical
175
+ units or physical Artifacts.
176
+
177
+ Before author worksets can materialize Candidate content, Context requires a
178
+ canonical `context.indexer.projected-artifact-plan/v1` and runs
179
+ `context.indexer.projected-artifact-fan-out-audit/v1`. Each projection binds a
180
+ stable projection key to an exact PartitionPlan group, Bundle digest, current
181
+ CLI policy-eligibility digest and evidence justification. Missing or mismatched
182
+ owner, Bundle variant or evidence increments the unassigned count; complete
183
+ Bundles, expanded variants, semantic split parts and the single CLI
184
+ `catalog-fallback` parent do not. Counts up to 100 continue, 101 through 300
185
+ continue with a warning, and counts above 300 return the non-Gate
186
+ `indexer-plan-revision-required` outcome before any author workset runs. That
187
+ partial outcome consumes neither a user Gate nor the three-attempt profile
188
+ revision ledger.
189
+
190
+ Artifact content has three mechanically separate layers. `facts[]` contains
191
+ canonical, source-bound values and never reader prose. A structured
192
+ `deterministic-block` contains only a registered renderer and `fact_refs`; the
193
+ CLI resolves those Facts and derives both Markdown and evidence, so a Provider
194
+ cannot relabel arbitrary JSON or prose as a catalog. A `semantic-prose` block
195
+ contains evidence-bound Markdown and cannot cite Facts as a way to increase
196
+ deterministic coverage. The normalized rendered Section retains ordered
197
+ `content_blocks` with the layer, Fact refs, evidence refs and per-block digest;
198
+ its Section digest covers that ledger and the exact reader-visible Markdown.
199
+
200
+ `ArtifactResult` also carries
201
+ `context.indexer.capability-group-evidence/v1`. It repeats the complete member
202
+ set bound by the author workset even when no capability group is selected. A
203
+ non-empty capability group has a stable ref derived only from the logical unit
204
+ and capability key, at least two explicit member-to-evidence bindings, and one
205
+ or more actual Artifact Section evidence bindings. A member cannot belong to
206
+ two capability groups. Every member evidence ref must be a current Result
207
+ evidence binding and must be visible in one of the declared Sections. Unknown
208
+ members or Sections, page-level evidence without Section consumption, and
209
+ workset/member-set drift are rejected. This protocol does not assign projection
210
+ dispositions to members outside capability groups.
211
+
212
+ ## Full-path example identity
213
+
214
+ Providers report normalized example observations through
215
+ `context.indexer.example-inventory/v1`. The stable `example_ref` is derived
216
+ only from the public target ref, scenario key and full path relative to the
217
+ authorized source/module root. Paths use Unicode NFC and `/`; absolute paths
218
+ and parent traversal are invalid. Source/module identity, content digest and
219
+ evidence form a separate observation ref, so additional evidence for the same
220
+ observation can merge without changing the example identity.
221
+
222
+ Context recomputes `context.indexer.example-identity-audit/v1`. Equal basenames
223
+ under different full paths are distinct examples, as are equal paths for
224
+ different targets or scenarios. Multiple distinct source/content observations
225
+ for the same complete example identity are a hard
226
+ `example-identity-collision`; a Provider cannot override the audit result or
227
+ forge an empty collision list. Candidate disposition and linkage are separate
228
+ downstream contracts.
229
+
230
+ ## SubjectKey schema authority
231
+
232
+ Community profile identity rules have one authority: the top-level
233
+ `subject_key_schemas` array in the CLI profile contract. A community Provider
234
+ manifest cannot copy or replace that schema. A namespaced additional profile
235
+ has the other allowed authority: the exact owner Provider's
236
+ `composition.extensions[].subject_key_schema`. The extension declaration is
237
+ required and may use only the CLI's closed namespace/local-key derivation
238
+ operators, kind identifiers and normalization rules.
239
+
240
+ Final selection resolves both forms to
241
+ `context.indexer.resolved-subject-key-schema/v1`. The record binds the Indexer,
242
+ profile, base-contract or Provider authority, schema digest and resolution
243
+ digest. Its canonical set digest is part of the stable final selection report;
244
+ transport paths and runtime receipts are not. Subject keys must match a kind in
245
+ the resolved schema and satisfy its normalization before they can become a
246
+ canonical NodeRef.
247
+
248
+ An unchanged schema is equivalent. Adding a kind while preserving the existing
249
+ namespace, normalization and local-key operators is compatible. Removing or
250
+ changing an existing identity derivation is identity-breaking: the owning
251
+ authority must advance its major version and the schema version must increase.
252
+ When approved Nodes exist, Context requires a non-delegable
253
+ `confirm-subject-reidentification` authorization bound to the exact old/new
254
+ schema digests, approved catalog, complete deterministic mapping and report.
255
+ Missing mappings, one old Node mapping to multiple Nodes, multiple old Nodes
256
+ colliding on one new Node, stale authorization or digest drift blocks
257
+ activation. With no approved Node, the human Gate is omitted but conformance
258
+ and major-version checks still apply.
259
+
260
+ ## Requirement change authority
261
+
262
+ `context.indexer.requirement-change-report/v1` retains both complete
263
+ requirements, their digests, the canonical comparator inputs, the recomputed
264
+ comparison and its report digest. Equivalent and strengthening changes use
265
+ `confirm-index-requirements` and may follow managed review authority.
266
+ Contraction or incomparable replacement instead uses
267
+ `confirm-index-requirement-contraction`; its confirmation is always human and
268
+ non-delegable, and binds the exact old/new requirement, comparison and report
269
+ digests. A self-digested caller classification is insufficient because Context
270
+ recomputes the comparator before issuing or consuming the confirmation.
271
+
272
+ Material-gap severity remains derived from the current requirement domain:
273
+ `required` is blocking, `optional` is recommended and `out-of-scope` creates no
274
+ gap. Severity is not written into worksets or the retained ledger, so a domain
275
+ change must pass the requirement Gate instead of editing a stored severity.
276
+
277
+ ## Provider discovery and composition Route
278
+
279
+ `configure-indexer-providers` is a static Agent Action. It reports the exact
280
+ CLI-bundled catalog together with other Indexer entry Skills already visible to
281
+ the current Host, then returns a path-free
282
+ `context.indexer.provider-route-input/v1`. The visible list remains
283
+ conversation-only: the protocol carries names, readable versions and source
284
+ types, never installation or cache paths, and the CLI does not scan for more
285
+ Skills. When the Host exposes an exact Skill root, discovery may read only the
286
+ Skill frontmatter and sibling `context-indexer.yaml`; the manifest version is
287
+ authoritative and its `metadata.context-provider-version` copy must match.
288
+ Conversational output groups the same Skill name and exact version into one
289
+ item with all observed source types, while `visible_skills` retains distinct
290
+ source observations because its `source_type` field is singular. Identical
291
+ bundled and installed observations are not separate Providers and never create
292
+ selection precedence; different exact versions remain separate identities.
293
+
294
+ `route-indexer-provider-selection` recomputes required
295
+ requirement/domain/source/module owner cells against the unchanged applied
296
+ requirement set. Read-scope overlap is reported but remains legal. A closed
297
+ selection may contain multiple fixed Skill identities and continues as one
298
+ `multi-skill` composition to `validate-indexer-selection-proposal`. Duplicate
299
+ primary owners instead return `indexer-provider-conflict` and cannot be
300
+ resolved by YAML or discovery order.
301
+
302
+ If a first pass leaves an owner cell unmatched, the Graph records `partial` and
303
+ runs `configure-community-indexer-fallback`. The second pass is explicitly
304
+ marked `community_fallback_attempted: true`; any remaining unowned required
305
+ cell becomes `indexer-customization-required` with its exact owner cell,
306
+ coverage capability and `context.indexer.capability-gap-proof/v1`. This is the
307
+ only Provider-discovery outcome that authorizes the local-customization Route;
308
+ the proof protocol remains a capability audit artifact rather than a second
309
+ Graph outcome. Only `selection-validation-required` returns a selection
310
+ proposal input. The Route writes no workspace or runtime state, and neither a
311
+ visible-Skill claim nor the Route report authorizes Bundle materialization.
312
+
313
+ ## Contract overlay validation
314
+
315
+ `validate-indexer-contract-overlays` recomputes the complete data-only overlay
316
+ against the exact CLI base and operator contracts. Invalid DSL, executable
317
+ fields, identity redefinition, threshold weakening, digest drift or a partial
318
+ Provider identity fails validation. The selected Provider Bundle integrity is
319
+ an exact input, not a self-reported trust assertion.
320
+
321
+ Successful validation emits
322
+ `context.indexer.overlay-validation-receipt/v1`. The receipt binds the exact
323
+ project, overlay, base contract, operator contract, Provider Bundle integrity
324
+ and canonical conformance report. There is no signature, KMS, trust-bundle or
325
+ overlay-authorization protocol. Changing any bound digest requires
326
+ revalidation; a stale receipt cannot be reused.
327
+
328
+ ## Question amendment back-edge
329
+
330
+ A CLI base-contract question can be expanded and confirmed before Provider
331
+ resolution. `context.indexer.base-question-amendment/v1` copies the complete
332
+ canonical contract from the selected base profile, changes only the requirement
333
+ question binding, and applies the confirmed snapshot with an expected-base CAS
334
+ and durable single-file journal. A Skill question ref is guidance only; it
335
+ cannot provide or alter the contract payload.
336
+
337
+ An overlay-backed question follows a different sequence. Context first
338
+ recomputes overlay DSL conformance and verifies the exact validation receipt.
339
+ Only then may
340
+ `context.indexer.overlay-question-amendment/v1` expand namespaced question and
341
+ target-domain additions from that overlay. The target coverage domain must
342
+ already be in scope and have one existing primary owner. The amendment is a
343
+ pure strengthening and remains in runtime staging after confirmation; it is not
344
+ written as a standalone requirement update.
345
+
346
+ The executable sequence is
347
+ `propose-overlay-question-amendment`,
348
+ `confirm-overlay-question-amendment`, then
349
+ `rebind-indexer-selection-to-requirement`. Proposal and rebind inputs carry the
350
+ exact overlay validation input and result; Context recomputes and
351
+ compares that pair instead of accepting a detached receipt. Confirmation emits
352
+ the exact amendment decision and performs no project write.
353
+
354
+ The rebind Action then proves that Indexer/provider
355
+ identity, operations, scopes, profile composition, requirement bindings, owner
356
+ closure and read authority are byte-identical. It revalidates overlay
357
+ conformance,
358
+ reuses the exact staged Bundles, and reruns both static and final selection
359
+ against the target requirement digest. Provider and SubjectKey authority must
360
+ remain unchanged. Final selection resolves every CLI-base question back to its
361
+ exact selected profile contract and requires one current validation proof
362
+ for every overlay question; forged bindings and duplicate, stale, or unused
363
+ proofs fail before the final report is issued. The report binds the resulting
364
+ question authority set digest. The resulting
365
+ `context.indexer.overlay-question-registry-apply-proposal/v1` contains the full
366
+ target `src/indexers.yaml` snapshot and binds the amendment, confirmation,
367
+ overlay validation, rebound selection, SubjectKey schema set and finalized reports.
368
+ The proposal goes through the same `stage-indexer-project-proposal` and
369
+ `apply-indexer-project` Actions as ordinary registry/customization proposals.
370
+ The latter dispatches this typed proposal to one expected-base CAS, project
371
+ write lock and persistent journal, so the requirement binding and rebound
372
+ registry are committed by one complete file replacement. Recovery observes
373
+ only the old or new registry snapshot; it never reconstructs authority from a
374
+ temporary Provider path.
375
+
376
+ ## Controlled invocation
377
+
378
+ `context.indexer.controlled-invocation/v1` binds:
379
+
380
+ - the exact Indexer, Provider, version, Bundle integrity and stable Provider
381
+ fingerprint;
382
+ - the manifest-declared `runtime + entry + args`;
383
+ - requested and granted Context SDK capabilities;
384
+ - an exact fixed dependency set with package, version, lock integrity and
385
+ resolved content digest;
386
+ - one authorized source/module scope;
387
+ - a stable trust-policy and authority digest;
388
+ - timeout and stdin/stdout/stderr byte limits.
389
+
390
+ The 0.7.0 built-in Host capability is `sandboxed_program: false`. A first-party,
391
+ verified or exact project-authorized program may use the `trusted-program` path,
392
+ which is not an isolation claim. An untrusted program without a real sandbox is
393
+ not executable.
394
+
395
+ The program input remains the operation-discriminated
396
+ `context.indexer.run-request/v1` (`main-index` or `material-answer`). Its output
397
+ is `context.indexer.run-result/v1`, wrapped by
398
+ `context.indexer.controlled-program-result/v1` to bind the exact invocation and
399
+ payload digest. Context still validates the operation-specific Result and
400
+ recomputes mechanical gates independently.
401
+
402
+ ## Primary execution identity and workset reads
403
+
404
+ Context derives `context.indexer.primary-registry-projection/v1` from the
405
+ finalized registry. The projection contains the selected Indexer's requirement
406
+ bindings, read scope, `main-index` operation, primary/additional profiles,
407
+ primary or pre-authority Provider layers and customization mode. It excludes
408
+ `profile.composers[]` and Provider layers used only after primary authoring.
409
+ `context.indexer.primary-execution-projection/v1` separately binds the primary
410
+ program, instructions, templates, config, CLI/profile contracts and only
411
+ `primary | pre-authority` resources. Its resource subprojection produces
412
+ `primary_resource_binding_digest`; a post-author resource cannot satisfy that
413
+ schema.
414
+
415
+ `context.indexer.main-workset/v1` digests its complete canonical payload. A
416
+ workset set permits only one author workset for an Indexer, owner cohort and
417
+ group key. `context.indexer.main-transport-batch/v1` may carry several complete
418
+ worksets but intentionally has no batch identity, digest, page number or
419
+ reader-facing name. Regrouping worksets for Host transport therefore cannot
420
+ change an individual workset or Result identity.
421
+
422
+ Each partition run request also carries one exact
423
+ `partition_strategy_attempt`: its resolution order, strategy reference and
424
+ digest, plus the previous attempt digest after a retry. The field participates
425
+ in the execution request digest and is `null` for author work. Context accepts
426
+ only a semantic partition. Ordinal, fixed-count and alphabetical axes are
427
+ recorded in a content-addressed convergence chain and atomically requeue the
428
+ same workset with the next authorized strategy. This path has no user Gate and
429
+ does not consume profile-revision attempts; an exhausted strategy set routes
430
+ to the CLI catalog fallback.
431
+
432
+ Source and evidence are read through
433
+ `context.indexer.workset-read-request/v1`. The stable request identity binds the
434
+ current workset, read kind and exact authorized ref set. Cursor and page size
435
+ are transport fields and do not enter that identity. Every response carries a
436
+ digest of its canonical page payload; cursor fields are again excluded. The
437
+ CLI closes a complete, acyclic cursor chain into
438
+ `context.indexer.workset-read-receipt/v1`, requiring exact coverage of the
439
+ requested refs. A main Result contains the canonically sorted receipt digest
440
+ set, and operation validation compares it with the actual CLI-issued receipts.
441
+ Changing a cursor, page size, call grouping or Host batch cannot manufacture a
442
+ new logical unit such as `batch-1` or alter an Artifact identity.
443
+
444
+ Post-author composition uses its own
445
+ `context.indexer.post-author-run-ledger/v1`; it never reuses primary main-run
446
+ progress. Each entry is keyed by composer ref and current workset digest and is
447
+ `pending`, `running`, `accepted`, `failed` or `stale`. An accepted entry stores
448
+ the complete validated Result, materialized fragments and invocation receipt,
449
+ including a valid zero-fragment Result. Rebuilding a workset set reuses only an
450
+ accepted entry whose workset, request, View, Result, receipt and fragment set
451
+ all remain current. A `running` entry without that complete record returns to
452
+ `pending` on recovery; a changed workset becomes `stale` without discarding
453
+ unchanged accepted peers.
454
+
455
+ `context.indexer.post-author-status/v1` exposes deterministic total, pending,
456
+ accepted, failed and stale counts, sorted next refs and the accepted receipt-set
457
+ digest. Zero effective composers yields `post_author_envelope.state =
458
+ not-required` without creating a View or envelope and may reconcile. A nonzero
459
+ set may reconcile only when every composer is accepted and the supplied
460
+ `context.indexer.composed-result-envelope/v1` exactly matches the recomposed
461
+ current envelope. Missing or mismatched envelope data is `stale`; partial,
462
+ failed or stale worksets cannot reconcile.
463
+
464
+ ## Parser coordinates and locks
465
+
466
+ A runtime profile declares each parser as a
467
+ `context.indexer.parser-requirement/v1`: an abstract capability, parser ABI and
468
+ exact community package/export/version coordinate. The capability name is not
469
+ an import alias and the presence of parser source in a Context or downstream source mirror
470
+ does not prove that the capability is installed.
471
+
472
+ The configured registry resolves that requirement to
473
+ `context.indexer.parser-coordinate-mapping/v1`. A direct mapping preserves the
474
+ community coordinate exactly. A wrapper may use another coordinate only while
475
+ preserving the same ABI digest; it may re-export the ABI but cannot redefine
476
+ parser facts. Installation then produces
477
+ `context.indexer.parser-resolution-lock/v1`, which records the actual
478
+ package/export/version, mapping digest, lock integrity, resolved content digest
479
+ and ABI digest.
480
+
481
+ Provider or local-customization imports must carry the exact capability and
482
+ parser lock digest and must import the actual locked package/export/version.
483
+ The locked dependency projection feeds controlled execution and stale
484
+ identity. Community aliases, mirror paths and whether a sync copied parser
485
+ source are not accepted as runtime evidence. Internal release smoke must load
486
+ the configured actual export; that later release check does not change this
487
+ protocol authority.
488
+
489
+ ## Section collection mapping and layout
490
+
491
+ Collection remains the closed package and query classification vocabulary. A
492
+ Provider Result declares only each Section's `section_key`, owner Indexer,
493
+ document kind, reader goal and Artifact kind. The selected CLI profile contract
494
+ owns the versioned `layout_mappings`; exactly one mapping must match the
495
+ profile, source role and complete Section projection. A Result containing a
496
+ collection, output path or unknown top-level package namespace is invalid.
497
+
498
+ Collection belongs to a physical Artifact. Every actual or material-gap
499
+ Section in that Artifact must resolve to the same collection. A mixed source
500
+ may route different Sections to different collections only by declaring
501
+ separate Artifacts in its validated Bundle; the CLI does not silently split or
502
+ merge reader pages to repair a Provider Result.
503
+
504
+ The compile-internal resolver emits `context.indexer.layout-proposal/v1`. It
505
+ binds the exact Artifact Result, profile contract, validated SubjectKey schema
506
+ set and exact schema digest, Indexer and source. The resolver validates the
507
+ SubjectKey against the selected schema normalization before deriving NodeRef;
508
+ a caller-supplied digest is not accepted as schema authority. NodeRef plus the
509
+ logical Artifact id/kind derives ArtifactRef. NodeRef, owner Indexer, Artifact
510
+ kind and Section key derive a stable logical Section identity; its placement
511
+ under one Artifact derives SectionRef. This lets a diff distinguish a moved
512
+ Section from new content without allowing the same logical Section to have two
513
+ primary placements. The ViewRef is an internal projection. Output paths are
514
+ derived under `knowledge/<collection>/` and never accepted from a Provider.
515
+
516
+ Template Artifacts enter layout only after validated rendering. Only rendered
517
+ Sections exist; an omitted optional projection does not create an empty
518
+ Section, while a retained material gap remains a planned landing without
519
+ reader-visible placeholder content. Artifact Bundle purpose and `split_of`
520
+ lineage are retained in the proposal. A proposal set rejects duplicate Node
521
+ owners, Artifact identities, logical Section identities, Section placements
522
+ and output paths across Indexers, as well as missing, nested or kind-changing
523
+ semantic-split parents.
524
+
525
+ Before Candidate Review, Context builds
526
+ `context.indexer.artifact-manifest/v1` from the current layout set and the
527
+ actual physical Markdown set. The manifest stores paths, content digests,
528
+ byte/body-line counts and exact logical-unit or registered-navigation ownership;
529
+ it does not retain the Markdown body. A separate
530
+ `context.indexer.physical-artifact-audit/v1` recomputes Bundle numerator and
531
+ denominator, per-unit physical fan-out, semantic split count, and the complete
532
+ missing/empty/orphan/unresolved-material sample set. Any such diagnostic is a
533
+ non-overridable completeness failure.
534
+
535
+ Generated navigation must use a content-addressed
536
+ `context.indexer.navigation-artifact-plan/v1`. Nested navigation is allowed,
537
+ but every navigation Artifact must reach a logical-unit Artifact; unknown
538
+ children, cycles, path collisions and unregistered files fail. Reader bodies
539
+ over 1500 lines produce a non-blocking advisory only. Total physical Artifact
540
+ count has no global maximum.
541
+
542
+ An initial layout does not create a structural Gate. A content-only increment
543
+ reuses the existing Artifact identity and also skips the Gate. Adding reader
544
+ fan-out to an already approved Node, removing or renaming an Artifact,
545
+ splitting/merging its declared lineage, moving a logical Section, or changing
546
+ an approved collection/path is represented by a digest-bound layout change
547
+ report and requires the human, non-delegable `confirm-layout-change` Gate.
548
+ `context.indexer.layout-transition/v1` first validates an explicit
549
+ no-planned-output state or a material-answer actualization whose digest and
550
+ actual ArtifactRef/SectionRef all belong to the current proposal set; only
551
+ then does it expose the conditional Gate. Replacing the proposal set makes the
552
+ prior actualization stale. The legacy align Route remains available only until
553
+ the workflow cutover; it is not an authority for the new Indexer protocol.
554
+
555
+ ## Explicit Result-bound Candidate compile
556
+
557
+ `compile-indexer-candidates` consumes the complete current set of accepted
558
+ author Results from the durable main-run store. Its input repeats only the
559
+ exact workset, execution-request, acceptance and Artifact Result digests; the
560
+ CLI rejects a missing, extra, forged or stale Result reference before
561
+ materialization. Callers cannot provide an alternate Result body, Provider
562
+ contract, default plan or prose-compile payload.
563
+
564
+ The compiler validates every accepted run envelope and acceptance record,
565
+ then binds each Candidate to the same Indexer Result, source identity,
566
+ Provider layer and integrity, Bundle digest, configuration fingerprint and
567
+ optional customization fingerprint used by layout. The supplied layout
568
+ proposal set and transition must bind the same Artifact Result set. Any
569
+ destructive layout report additionally requires its exact non-delegable
570
+ confirmation; unresolved material gaps stop compile.
571
+
572
+ Structured Section blocks are materialized directly. Template-backed
573
+ Artifacts use only an exact rendered Artifact bound to the same Result digest.
574
+ The CLI derives physical paths from layout, builds the physical Artifact
575
+ manifest, and requires the completeness audit to pass before returning the
576
+ Candidate set. The durable current record lives under Context runtime state;
577
+ it does not write approved knowledge. Review and apply remain the only route
578
+ to approved Markdown.
579
+
580
+ No generic fallback exists after Provider resolution. A minimal local
581
+ customization may be proposed only after the explicit
582
+ `indexer-customization-required` outcome and its capability-gap proof; compile
583
+ itself never invents one.
584
+
585
+ ## Material-answer dispatch, baseline, Review, and layout actualization
586
+
587
+ `context.indexer.material-question-workset/v1` is built only by the CLI after a
588
+ material-gap checkpoint. It binds the current requirement and registry digests,
589
+ question contract and target inventory, source-input digests, exact question
590
+ revision, predecessor ledger revision, authorized sources, and eligible answer
591
+ Indexers. Eligibility is derived from the registry-enabled `material-answer`
592
+ operation, an enricher binding, the primary Provider manifest, read scope, and
593
+ the evidence-kind intersection; callers cannot add an eligible Indexer.
594
+
595
+ The CLI creates one `context.indexer.run-request/v1` per eligible answer Indexer.
596
+ Its Provider composition fingerprint is recomputed from the answer Indexer,
597
+ exact final Provider authority, and layer-composition view digest. The separate
598
+ material-answer run ledger uses CAS transitions and content-addressed accepted
599
+ records. A complete accepted empty Result is recovered without another dispatch;
600
+ an interrupted running entry without its accepted record returns to pending.
601
+ Before acceptance, every evidence claim must resolve through an exact current
602
+ source-span read receipt, and unused or stale receipts are rejected.
603
+
604
+ A `material-answer` Result cannot move a retained gap directly to an approved
605
+ state. Context first validates the exact workset, question revision, eligible
606
+ Indexer, Provider fingerprint, source authority, canonical spans, evidence
607
+ content digests, provenance selector and minimum item/origin counts. Only a
608
+ passing candidate can produce
609
+ `context.indexer.material-answer-baseline-report/v1`. Its fixed Review scope is
610
+ `question-target-source-span-evidence-binding`; the strict schema has no field
611
+ for approving a reader page, Artifact content or final knowledge candidate.
612
+
613
+ `context.indexer.material-answer-review-decision/v1` binds that report, the
614
+ candidate set, workset, question revision and binding digest. Applying an
615
+ `approved` decision uses the workset's predecessor ledger revision as a CAS
616
+ base, consumes that workset and records the decision digest in the canonical
617
+ answer binding. A successor ledger revision does not make the consumed workset
618
+ self-stale. A rejected, insufficient, forged or differently scoped decision
619
+ cannot create `answer-approved` state.
620
+
621
+ Layout uses an unapplied
622
+ `context.indexer.material-answer-layout-proposal/v1`. Each planned or existing
623
+ answer landing must map uniquely to an actual `node:`, `artifact:` or
624
+ `section:` ref. Before creating a resolved actualization, Context recomputes
625
+ `context.indexer.material-answer-evidence-compatibility/v1` from the retained
626
+ canonical evidence and current question/source authority. A changed source set,
627
+ origin, snapshot, kind, span, content digest, provenance rule or minimum count
628
+ reopens the gap to `unresolved`. A missing or colliding landing remains
629
+ `answer-approved`; rejecting or replacing a layout proposal invalidates its
630
+ resolved mappings back to `answer-approved`.
631
+
632
+ `context.indexer.material-answer-flow-status/v1` is the admission fact for the
633
+ next stages. An unresolved blocking gap stops layout. An `answer-approved`
634
+ blocking gap may enter layout but cannot consume a conditional layout Gate or
635
+ enter the main Candidate Review. Those two admissions become true only when
636
+ every blocking answer has a current actualization for the exact layout digest.
637
+ Optional gaps remain reported but do not become blocking. Final close removes
638
+ a resolved ledger entry only when the approved structure projection carries
639
+ the same question, binding, actualized target and complete canonical evidence
640
+ ref set.
641
+
642
+ ## Detector and inspector
643
+
644
+ An activation detector consumes `context.indexer.activation-request/v1`. The
645
+ request contains the exact declared required, supporting and negative signal
646
+ set plus one `context.indexer.parser-fact-view/v1`. The view is built from
647
+ validated Evidence Adapter Results and their process-local structured fact
648
+ payload sidecars. It binds the authorized source/module scope, canonical file
649
+ inventory, origin Result digests and every payload digest. Raw source or
650
+ configuration text is not part of this input.
651
+
652
+ Parser adapters expose a materialization helper that returns the wire-safe
653
+ `context.indexer.evidence-adapter-result/v1` together with `fact_payloads`.
654
+ Those payloads intentionally do not serialize inside the Result and cannot be
655
+ recovered after a JSON round trip. The caller must construct the parser fact
656
+ view while the sidecar is still present; missing, extra, stale or out-of-view
657
+ payloads fail closed.
658
+
659
+ `context.indexer.activation-result/v1` must close every signal as
660
+ `present`, `absent` or `unknown`; a present signal requires evidence. Context,
661
+ not the detector, derives `matched`, `not-matched` or `indeterminate`.
662
+
663
+ An authoring inspector consumes `context.indexer.inspector-request/v1` and
664
+ returns `context.indexer.inspector-result/v1`. Its evidence payload is the
665
+ shared `context.indexer.evidence-adapter-result/v1`. Inspector files are always
666
+ `enricher` plus `lightweight-evidence`; they cannot own baseline inventory or
667
+ contribute a denominator. The Result must close the requested inventory and
668
+ authorized source/module scope. Detector and inspector entries run only from
669
+ the reverified content-addressed stage through the same empty-environment,
670
+ no-shell, bounded JSON subprocess runner. Timeout, stdin/stdout/stderr overflow,
671
+ invalid UTF-8/JSON, undeclared evidence and scope expansion are typed failures;
672
+ a successful execution returns a digest-bound receipt.
673
+
674
+ ## Project-local customization
675
+
676
+ A Provider-only project does not create `src/indexer/`. When the registry
677
+ explicitly selects `extend` or `replace`, Context reads only
678
+ `src/indexer/<indexer-id>/` and the fixed resources `index.ts`, `variables.ts`,
679
+ `helpers.ts`, `instructions.md` and `templates/<id>.md`. Each file requires an
680
+ exact `@context-indexer-origin` header. `replace` additionally requires a current
681
+ capability-gap proof.
682
+
683
+ Every customization view also carries a validated
684
+ `context.indexer.customization-plan/v1`. The fixed escalation ladder is
685
+ `provider-only`, `config`, `instructions-append`, `template-override`,
686
+ `program-extend`, then `replace`. Selecting a step requires ordered evidence
687
+ that every smaller step is insufficient. `replace` additionally requires three
688
+ distinct failed extension-attempt digests and human confirmation; adding an
689
+ external dependency also makes confirmation mandatory. The selected step must
690
+ match the actual loaded files and the registry's `none | extend | replace`
691
+ mode. A Provider-only workspace gets a deterministic `provider-only` plan and
692
+ must not supply a local escalation plan. A non-empty registry config remains
693
+ registry-only but requires an exact `config` plan with Provider-only closure
694
+ evidence.
695
+
696
+ Project changes are represented by
697
+ `context.indexer.project-proposal/v1`. A proposal binds the unchanged
698
+ requirement-set authority, complete target registry, actual changed files,
699
+ fixed dependency intents, validation reports and expected-base digests. It is
700
+ staged under runtime state before any source write. Applying it uses the project
701
+ write lock and a persistent multi-file journal; recovery accepts only complete
702
+ base or target file states and refuses unknown external drift.
703
+
704
+ Dependency intents begin as `requires-authorization` and cannot make a proposal
705
+ apply-ready. The separate `authorize-indexer-dependencies` Gate requires the
706
+ `context.indexer-dependency-install` authority and binds the proposal, original
707
+ intent-set digest, exact package versions, importers, lock integrity, resolved
708
+ content digests and authority scope. Its CLI Action returns a digest-bound
709
+ authorization receipt plus a new `locked` intent set; install scripts remain
710
+ structurally `false`. A locked intent without its exact receipt, an unused
711
+ receipt, a changed resolution or an ordinary managed authority fails closed.
712
+ The Agent must use that locked set and the complete package/lock snapshots in a
713
+ replacement staged proposal before `apply-indexer-project`; the apply journal
714
+ never writes `node_modules`, which is reconstructed only from the accepted lock.
715
+
716
+ ## Indexer template rendering
717
+
718
+ Indexer authoring templates are not package-output Handlebars templates. Each
719
+ Provider template is one manifest-declared Markdown file under that Provider's
720
+ `templates/` tree. A project may replace only the same template id/profile at
721
+ `src/indexer/<indexer-id>/templates/<id>.md`; all other templates continue to
722
+ come from the verified, content-addressed Provider stage.
723
+
724
+ The Markdown file begins with closed YAML frontmatter using
725
+ `context.indexer.template/v1`. It declares the reader goal, applicable artifact
726
+ policy variants, typed variables with an explicit `deterministic-fact` or
727
+ `semantic-prose` content layer, registered deterministic blocks, required and
728
+ optional Sections, question refs, evidence kinds/cardinality, deletion rules,
729
+ page-boundary guidance, anonymous examples, anti-examples, forbidden output and
730
+ a rendered byte budget. Every body Section uses exact markers:
731
+
732
+ ```md
733
+ <!-- context:indexer-section summary -->
734
+ # {{variable:title}}
735
+
736
+ {{variable:summary}}
737
+ <!-- /context:indexer-section -->
738
+ ```
739
+
740
+ Only `{{variable:<id>}}` and `{{block:<id>}}` are accepted. Direct variables are
741
+ semantic prose. A block source variable is a deterministic Fact projection,
742
+ must bind canonical `fact_refs`, and must equal the CLI's normalized projection
743
+ of those Facts. Blocks select one of
744
+ the CLI-owned `bullet-list`, `key-value-table` or `json-code-block` renderers;
745
+ templates cannot register code or helpers. A block directive occupies its own
746
+ template line so the renderer can retain an exact content-layer boundary. The
747
+ contract and body must declare exactly the same Sections and placeholders.
748
+
749
+ `ArtifactResult` binds every template variable to current evidence refs and
750
+ binds every declared Section to `section_key`, owner Indexer, document kind,
751
+ reader goal and Artifact kind. Rendering validates the Provider/customization
752
+ fingerprints, template digest, current CLI-owned applicability conditions,
753
+ variable types and expansion limits, per-variable evidence boundary and exact
754
+ CLI-owned question target. An optional Section without data
755
+ or sufficient evidence is absent from the rendered Candidate. A required
756
+ Section in the same state becomes the already-declared material-question
757
+ transition and makes `review_ready` false.
758
+
759
+ Before a Candidate can enter Review, Context rejects unknown directives,
760
+ unresolved variables, template comments, example placeholders, standalone or
761
+ bracketed `TODO`/`TBD`/`待补充`/`待生成` markers, title-only Sections and budget
762
+ overflow. A source-backed sentence that discusses a known TODO is not treated
763
+ as a placeholder merely because it contains that token; it remains semantic
764
+ prose and therefore requires Agent Review. The rendered
765
+ Section content, ordered content-layer ledger and evidence receive stable
766
+ digests. Deterministic blocks contribute catalog completeness but never
767
+ semantic-prose density. Later `build` projects this approved body; it does not
768
+ perform a first render or change its structure.
769
+
770
+ An ArtifactResult may emit
771
+ `context.indexer.structured-claim-set/v1`. Every claim binds a stable claim
772
+ kind and subject to one real Artifact/Section owner and one or more evidence
773
+ refs carried by that exact Section. The subject must be the current logical
774
+ unit, one of its CLI-owned inventory members, or an authorized target-resolution
775
+ identity. Missing owners, outside subjects, unknown evidence and evidence that
776
+ is known globally but absent from the owner Section all fail Result validation.
777
+
778
+ Main-run validation derives
779
+ `context.indexer.generated-authoring-audit/v1`. It reports controlled generated
780
+ placeholder and empty emitted-Section hard findings, proves that every emitted
781
+ structured claim passed owner-local evidence coverage, and lists every
782
+ semantic-prose block or direct authored template variable as
783
+ `semantic-prose-agent-review-required`. It does not scan free prose to claim
784
+ that unsupported natural-language assertions were mechanically detected.
785
+
786
+ ## Material-question target exclusion
787
+
788
+ A target exclusion is not a Provider Result and does not change the confirmed
789
+ requirement. Context first emits
790
+ `context.indexer.material-question-exclusion-report/v1` for one current
791
+ unresolved `QuestionTargetKey`. The report binds the project, predecessor
792
+ ledger revision, question-target inventory, question contract and revision,
793
+ target ref/item digest, exact allowlisted reason, derived severity and the
794
+ reader-visible impact.
795
+
796
+ `confirm-material-question-exclusion` accepts only that report and always emits
797
+ `context.indexer.material-question-exclusion-confirmation/v1` with human,
798
+ non-delegable authority. Managed mode, Provider omission, wildcard targets and
799
+ non-allowlisted reasons cannot create the decision. Apply revalidates the
800
+ report against the current resolved question and ledger before retaining only
801
+ the reason code and decision digest in the entry.
802
+
803
+ The successor ledger is checkpointed with the predecessor revision through the
804
+ same durable structure journal. A question contract, owner, target item,
805
+ question revision or other pair dependency change replaces the retained
806
+ exclusion with an unresolved entry in one checkpoint. The Material Gap ledger
807
+ is intentionally absent from the main-workset identity, so this target-level
808
+ decision does not invalidate unrelated main indexing worksets.