@c4a/context 0.6.18 → 0.7.0

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 (130) hide show
  1. package/README.md +5 -5
  2. package/README.zh-CN.md +5 -5
  3. package/codeIndexPlan.d.ts +84 -0
  4. package/contracts.d.ts +2 -1
  5. package/docs/README.md +7 -0
  6. package/docs/README.zh-CN.md +5 -0
  7. package/docs/getting-started.md +12 -12
  8. package/docs/guides/agent-guide.md +18 -9
  9. package/docs/guides/code-indexer-skill-authoring.md +124 -0
  10. package/docs/guides/indexer-provider-and-customization.md +140 -0
  11. package/docs/guides/lark-resources.md +7 -0
  12. package/docs/guides/markdown-indexer-skill-authoring.md +118 -0
  13. package/docs/guides/package-outputs.md +3 -3
  14. package/docs/reference/code-extractors.md +7 -6
  15. package/docs/reference/indexer-provider-protocol.md +819 -0
  16. package/docs/reference/package-templates.md +18 -10
  17. package/docs/reference/project-api.md +49 -24
  18. package/index.d.ts +48 -2
  19. package/index.js +28239 -3948
  20. package/indexerAgentStepProtocol.d.ts +9391 -0
  21. package/indexerArtifactDependencies.d.ts +689 -0
  22. package/indexerArtifactPolicy.d.ts +335 -0
  23. package/indexerArtifactResult.d.ts +2010 -0
  24. package/indexerAuditFacts.d.ts +66 -0
  25. package/indexerAuditOverrideReadiness.d.ts +27 -0
  26. package/indexerAuditProtocol.d.ts +238 -0
  27. package/indexerAuditRevision.d.ts +726 -0
  28. package/indexerAuditRevisionActions.d.ts +236 -0
  29. package/indexerAuthoringFixture.d.ts +152 -0
  30. package/indexerBaseQuestionAmendment.d.ts +2403 -0
  31. package/indexerBenchmark.d.ts +1062 -0
  32. package/indexerCandidateCompile.d.ts +801 -0
  33. package/indexerCapabilityGroupEvidence.d.ts +129 -0
  34. package/indexerCatalogFallback.d.ts +1262 -0
  35. package/indexerCollectionMapping.d.ts +75 -0
  36. package/indexerContentLayers.d.ts +137 -0
  37. package/indexerControlledInvocation.d.ts +512 -0
  38. package/indexerControlledProgram.d.ts +12535 -0
  39. package/indexerCoreExports.d.ts +21 -0
  40. package/indexerCustomizationDraft.d.ts +13800 -0
  41. package/indexerCustomizationLadder.d.ts +103 -0
  42. package/indexerDependencyView.d.ts +1610 -0
  43. package/indexerEvidenceAdapterResult.d.ts +504 -0
  44. package/indexerExampleDecision.d.ts +1606 -0
  45. package/indexerExampleIdentity.d.ts +132 -0
  46. package/indexerExampleIdentityAudit.d.ts +70 -0
  47. package/indexerExampleLinkageAudit.d.ts +80 -0
  48. package/indexerGeneratedAuthoringAudit.d.ts +208 -0
  49. package/indexerIncrementalImpact.d.ts +221 -0
  50. package/indexerInventoryDisposition.d.ts +443 -0
  51. package/indexerLayerComposition.d.ts +1652 -0
  52. package/indexerLayoutChange.d.ts +329 -0
  53. package/indexerLayoutProposalSet.d.ts +447 -0
  54. package/indexerLayoutResolver.d.ts +342 -0
  55. package/indexerLayoutTransition.d.ts +247 -0
  56. package/indexerLifecycle.d.ts +53 -0
  57. package/indexerMainLifecycle.d.ts +258 -0
  58. package/indexerMainRunLedger.d.ts +888 -0
  59. package/indexerMainRunProtocol.d.ts +6471 -0
  60. package/indexerMainWorkset.d.ts +2141 -0
  61. package/indexerMaterialAnswer.d.ts +738 -0
  62. package/indexerMaterialAnswerActualization.d.ts +91 -0
  63. package/indexerMaterialAnswerExecutionPlan.d.ts +2887 -0
  64. package/indexerMaterialAnswerFlow.d.ts +63 -0
  65. package/indexerMaterialAnswerLayout.d.ts +76 -0
  66. package/indexerMaterialAnswerReview.d.ts +217 -0
  67. package/indexerMaterialAnswerReviewRoute.d.ts +6145 -0
  68. package/indexerMaterialAnswerRunLedger.d.ts +918 -0
  69. package/indexerMaterialAnswerRunProtocol.d.ts +1253 -0
  70. package/indexerMaterialGapLedger.d.ts +3111 -0
  71. package/indexerMaterialQuestionExclusion.d.ts +129 -0
  72. package/indexerMaterialQuestionWorkset.d.ts +508 -0
  73. package/indexerNavigationArtifactGraph.d.ts +5 -0
  74. package/indexerNavigationArtifactPlan.d.ts +39 -0
  75. package/indexerOverlayQuestionAmendment.d.ts +2551 -0
  76. package/indexerOverlayQuestionApplyProposal.d.ts +4697 -0
  77. package/indexerOverlayTrust.d.ts +1425 -0
  78. package/indexerParserCoordinate.d.ts +222 -0
  79. package/indexerParserFactView.d.ts +503 -0
  80. package/indexerPartitionConvergence.d.ts +496 -0
  81. package/indexerPartitionPlan.d.ts +919 -0
  82. package/indexerPartitionStrategyResolution.d.ts +594 -0
  83. package/indexerPhysicalArtifactAudit.d.ts +247 -0
  84. package/indexerPhysicalArtifactManifest.d.ts +449 -0
  85. package/indexerPlannedMaterialAnswer.d.ts +116 -0
  86. package/indexerPostAuthorComposition.d.ts +2000 -0
  87. package/indexerPostAuthorRunLedger.d.ts +1972 -0
  88. package/indexerPrimaryProjection.d.ts +262 -0
  89. package/indexerProfileContract.d.ts +3034 -0
  90. package/indexerProfileMetricAudit.d.ts +218 -0
  91. package/indexerProgramExecutionAuthorization.d.ts +227 -0
  92. package/indexerProgramRunProtocol.d.ts +7642 -0
  93. package/indexerProjectProposal.d.ts +2807 -0
  94. package/indexerProjectedArtifactFanOutAudit.d.ts +159 -0
  95. package/indexerProjectedArtifactPlan.d.ts +217 -0
  96. package/indexerProtocolCommon.d.ts +29 -0
  97. package/indexerProvider.d.ts +2573 -0
  98. package/indexerProviderComposition.d.ts +1357 -0
  99. package/indexerProviderContractReferences.d.ts +13 -0
  100. package/indexerProviderProfileResolution.d.ts +20 -0
  101. package/indexerProviderResolution.d.ts +752 -0
  102. package/indexerProviderResolutionAction.d.ts +678 -0
  103. package/indexerProviderRouting.d.ts +3909 -0
  104. package/indexerProviderSelectionProposal.d.ts +3311 -0
  105. package/indexerQuestionAuthority.d.ts +419 -0
  106. package/indexerReaderTargetInventory.d.ts +161 -0
  107. package/indexerReferenceOnlyAudit.d.ts +90 -0
  108. package/indexerRegistry.d.ts +3019 -0
  109. package/indexerRequirementComparison.d.ts +44 -0
  110. package/indexerRequirementConfirmation.d.ts +1193 -0
  111. package/indexerRequirementLifecycle.d.ts +3314 -0
  112. package/indexerRestrictedSelector.d.ts +63 -0
  113. package/indexerResultReconciliation.d.ts +6844 -0
  114. package/indexerResultReconciliationRun.d.ts +15 -0
  115. package/indexerRunEnvelope.d.ts +384 -0
  116. package/indexerRunProtocolCommon.d.ts +21 -0
  117. package/indexerSharedArtifactFingerprint.d.ts +33 -0
  118. package/indexerStructuredDeclaration.d.ts +513 -0
  119. package/indexerSubjectCatalog.d.ts +230 -0
  120. package/indexerSubjectIdentity.d.ts +19 -0
  121. package/indexerSubjectKeyAuthority.d.ts +785 -0
  122. package/indexerTemplateRendering.d.ts +485 -0
  123. package/indexerToolSnapshot.d.ts +431 -0
  124. package/indexerWorksetRead.d.ts +287 -0
  125. package/package.json +1 -1
  126. package/phases.d.ts +11 -9
  127. package/templates/package-templates/kb/AGENTS.md +1 -1
  128. package/templates/package-templates/kb/skills/knowledge-query/SKILL.md +1 -1
  129. package/templates/package-templates.zh-CN/kb/AGENTS.md +1 -1
  130. package/templates/package-templates.zh-CN/kb/skills/knowledge-query/SKILL.md +1 -1
@@ -0,0 +1,819 @@
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 and trust
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
+ attestation/trust bundle fails before any authorization Route exists. A
319
+ resolver's self-reported `verified` value is not an accepted input.
320
+
321
+ A valid detached Ed25519 attestation is checked locally against a matching key
322
+ in the complete Host trust-bundle policy, including key validity and
323
+ revocation, and directly produces the common
324
+ `context.indexer.overlay-trust-receipt/v1`. The receipt binds the exact Host
325
+ adapter identity/version and management-authority digest as well as the policy
326
+ digest, so any policy-envelope drift makes the audit stale. An unsigned overlay, an attestation
327
+ without an installed trust bundle, or an attestation whose issuer/key is absent
328
+ from the canonical bundle returns `authorization-required`; the request binds
329
+ the exact attestation digest (or null) together with the
330
+ project/overlay/base/operator/Provider/conformance digest set. The
331
+ non-delegable `authorize-indexer-contract-overlay` Gate may issue that
332
+ project-exact authorization under the independent
333
+ `context.indexer-contract-overlay` authority; revalidation then produces the
334
+ same trust-receipt protocol with trust class
335
+ `project-authorized-exact-digest`. Cross-project or stale reports cannot be
336
+ reused. Once the bundle contains the declared issuer/key, an invalid signature,
337
+ expired key, revoked key, or malformed policy is a hard trust failure and
338
+ cannot downgrade to project authorization.
339
+
340
+ ## Question amendment back-edge
341
+
342
+ A CLI base-contract question can be expanded and confirmed before Provider
343
+ resolution. `context.indexer.base-question-amendment/v1` copies the complete
344
+ canonical contract from the selected base profile, changes only the requirement
345
+ question binding, and applies the confirmed snapshot with an expected-base CAS
346
+ and durable single-file journal. A Skill question ref is guidance only; it
347
+ cannot provide or alter the contract payload.
348
+
349
+ An overlay-backed question follows a different sequence. Context first
350
+ recomputes overlay DSL conformance and verifies an enterprise or exact-project
351
+ trust receipt. Only then may
352
+ `context.indexer.overlay-question-amendment/v1` expand namespaced question and
353
+ target-domain additions from that overlay. The target coverage domain must
354
+ already be in scope and have one existing primary owner. The amendment is a
355
+ pure strengthening and remains in runtime staging after confirmation; it is not
356
+ written as a standalone requirement update.
357
+
358
+ The executable sequence is
359
+ `propose-overlay-question-amendment`,
360
+ `confirm-overlay-question-amendment`, then
361
+ `rebind-indexer-selection-to-requirement`. Proposal and rebind inputs carry the
362
+ exact trusted overlay validation input and result; Context recomputes and
363
+ compares that pair instead of accepting a detached receipt. Confirmation emits
364
+ the exact amendment decision and performs no project write.
365
+
366
+ The rebind Action then proves that Indexer/provider
367
+ identity, operations, scopes, profile composition, requirement bindings, owner
368
+ closure and read authority are byte-identical. It revalidates overlay trust,
369
+ reuses the exact staged Bundles, and reruns both static and final selection
370
+ against the target requirement digest. Provider and SubjectKey authority must
371
+ remain unchanged. Final selection resolves every CLI-base question back to its
372
+ exact selected profile contract and requires one current trust/conformance proof
373
+ for every overlay question; forged bindings and duplicate, stale, or unused
374
+ proofs fail before the final report is issued. The report binds the resulting
375
+ question authority set digest. The resulting
376
+ `context.indexer.overlay-question-registry-apply-proposal/v1` contains the full
377
+ target `src/indexers.yaml` snapshot and binds the amendment, confirmation,
378
+ overlay trust, rebound selection, SubjectKey schema set and finalized reports.
379
+ The proposal goes through the same `stage-indexer-project-proposal` and
380
+ `apply-indexer-project` Actions as ordinary registry/customization proposals.
381
+ The latter dispatches this typed proposal to one expected-base CAS, project
382
+ write lock and persistent journal, so the requirement binding and rebound
383
+ registry are committed by one complete file replacement. Recovery observes
384
+ only the old or new registry snapshot; it never reconstructs authority from a
385
+ temporary Provider path.
386
+
387
+ ## Controlled invocation
388
+
389
+ `context.indexer.controlled-invocation/v1` binds:
390
+
391
+ - the exact Indexer, Provider, version, Bundle integrity and stable Provider
392
+ fingerprint;
393
+ - the manifest-declared `runtime + entry + args`;
394
+ - requested and granted Context SDK capabilities;
395
+ - an exact fixed dependency set with package, version, lock integrity and
396
+ resolved content digest;
397
+ - one authorized source/module scope;
398
+ - a stable trust-policy and authority digest;
399
+ - timeout and stdin/stdout/stderr byte limits.
400
+
401
+ The 0.7.0 built-in Host capability is `sandboxed_program: false`. A first-party,
402
+ verified or exact project-authorized program may use the `trusted-program` path,
403
+ which is not an isolation claim. An untrusted program without a real sandbox is
404
+ not executable.
405
+
406
+ The program input remains the operation-discriminated
407
+ `context.indexer.run-request/v1` (`main-index` or `material-answer`). Its output
408
+ is `context.indexer.run-result/v1`, wrapped by
409
+ `context.indexer.controlled-program-result/v1` to bind the exact invocation and
410
+ payload digest. Context still validates the operation-specific Result and
411
+ recomputes mechanical gates independently.
412
+
413
+ ## Primary execution identity and workset reads
414
+
415
+ Context derives `context.indexer.primary-registry-projection/v1` from the
416
+ finalized registry. The projection contains the selected Indexer's requirement
417
+ bindings, read scope, `main-index` operation, primary/additional profiles,
418
+ primary or pre-authority Provider layers and customization mode. It excludes
419
+ `profile.composers[]` and Provider layers used only after primary authoring.
420
+ `context.indexer.primary-execution-projection/v1` separately binds the primary
421
+ program, instructions, templates, config, CLI/profile contracts and only
422
+ `primary | pre-authority` resources. Its resource subprojection produces
423
+ `primary_resource_binding_digest`; a post-author resource cannot satisfy that
424
+ schema.
425
+
426
+ `context.indexer.main-workset/v1` digests its complete canonical payload. A
427
+ workset set permits only one author workset for an Indexer, owner cohort and
428
+ group key. `context.indexer.main-transport-batch/v1` may carry several complete
429
+ worksets but intentionally has no batch identity, digest, page number or
430
+ reader-facing name. Regrouping worksets for Host transport therefore cannot
431
+ change an individual workset or Result identity.
432
+
433
+ Each partition run request also carries one exact
434
+ `partition_strategy_attempt`: its resolution order, strategy reference and
435
+ digest, plus the previous attempt digest after a retry. The field participates
436
+ in the execution request digest and is `null` for author work. Context accepts
437
+ only a semantic partition. Ordinal, fixed-count and alphabetical axes are
438
+ recorded in a content-addressed convergence chain and atomically requeue the
439
+ same workset with the next authorized strategy. This path has no user Gate and
440
+ does not consume profile-revision attempts; an exhausted strategy set routes
441
+ to the CLI catalog fallback.
442
+
443
+ Source and evidence are read through
444
+ `context.indexer.workset-read-request/v1`. The stable request identity binds the
445
+ current workset, read kind and exact authorized ref set. Cursor and page size
446
+ are transport fields and do not enter that identity. Every response carries a
447
+ digest of its canonical page payload; cursor fields are again excluded. The
448
+ CLI closes a complete, acyclic cursor chain into
449
+ `context.indexer.workset-read-receipt/v1`, requiring exact coverage of the
450
+ requested refs. A main Result contains the canonically sorted receipt digest
451
+ set, and operation validation compares it with the actual CLI-issued receipts.
452
+ Changing a cursor, page size, call grouping or Host batch cannot manufacture a
453
+ new logical unit such as `batch-1` or alter an Artifact identity.
454
+
455
+ Post-author composition uses its own
456
+ `context.indexer.post-author-run-ledger/v1`; it never reuses primary main-run
457
+ progress. Each entry is keyed by composer ref and current workset digest and is
458
+ `pending`, `running`, `accepted`, `failed` or `stale`. An accepted entry stores
459
+ the complete validated Result, materialized fragments and invocation receipt,
460
+ including a valid zero-fragment Result. Rebuilding a workset set reuses only an
461
+ accepted entry whose workset, request, View, Result, receipt and fragment set
462
+ all remain current. A `running` entry without that complete record returns to
463
+ `pending` on recovery; a changed workset becomes `stale` without discarding
464
+ unchanged accepted peers.
465
+
466
+ `context.indexer.post-author-status/v1` exposes deterministic total, pending,
467
+ accepted, failed and stale counts, sorted next refs and the accepted receipt-set
468
+ digest. Zero effective composers yields `post_author_envelope.state =
469
+ not-required` without creating a View or envelope and may reconcile. A nonzero
470
+ set may reconcile only when every composer is accepted and the supplied
471
+ `context.indexer.composed-result-envelope/v1` exactly matches the recomposed
472
+ current envelope. Missing or mismatched envelope data is `stale`; partial,
473
+ failed or stale worksets cannot reconcile.
474
+
475
+ ## Parser coordinates and locks
476
+
477
+ A runtime profile declares each parser as a
478
+ `context.indexer.parser-requirement/v1`: an abstract capability, parser ABI and
479
+ exact community package/export/version coordinate. The capability name is not
480
+ an import alias and the presence of parser source in a Context or downstream source mirror
481
+ does not prove that the capability is installed.
482
+
483
+ The configured registry resolves that requirement to
484
+ `context.indexer.parser-coordinate-mapping/v1`. A direct mapping preserves the
485
+ community coordinate exactly. A wrapper may use another coordinate only while
486
+ preserving the same ABI digest; it may re-export the ABI but cannot redefine
487
+ parser facts. Installation then produces
488
+ `context.indexer.parser-resolution-lock/v1`, which records the actual
489
+ package/export/version, mapping digest, lock integrity, resolved content digest
490
+ and ABI digest.
491
+
492
+ Provider or local-customization imports must carry the exact capability and
493
+ parser lock digest and must import the actual locked package/export/version.
494
+ The locked dependency projection feeds controlled execution and stale
495
+ identity. Community aliases, mirror paths and whether a sync copied parser
496
+ source are not accepted as runtime evidence. Internal release smoke must load
497
+ the configured actual export; that later release check does not change this
498
+ protocol authority.
499
+
500
+ ## Section collection mapping and layout
501
+
502
+ Collection remains the closed package and query classification vocabulary. A
503
+ Provider Result declares only each Section's `section_key`, owner Indexer,
504
+ document kind, reader goal and Artifact kind. The selected CLI profile contract
505
+ owns the versioned `layout_mappings`; exactly one mapping must match the
506
+ profile, source role and complete Section projection. A Result containing a
507
+ collection, output path or unknown top-level package namespace is invalid.
508
+
509
+ Collection belongs to a physical Artifact. Every actual or material-gap
510
+ Section in that Artifact must resolve to the same collection. A mixed source
511
+ may route different Sections to different collections only by declaring
512
+ separate Artifacts in its validated Bundle; the CLI does not silently split or
513
+ merge reader pages to repair a Provider Result.
514
+
515
+ The compile-internal resolver emits `context.indexer.layout-proposal/v1`. It
516
+ binds the exact Artifact Result, profile contract, validated SubjectKey schema
517
+ set and exact schema digest, Indexer and source. The resolver validates the
518
+ SubjectKey against the selected schema normalization before deriving NodeRef;
519
+ a caller-supplied digest is not accepted as schema authority. NodeRef plus the
520
+ logical Artifact id/kind derives ArtifactRef. NodeRef, owner Indexer, Artifact
521
+ kind and Section key derive a stable logical Section identity; its placement
522
+ under one Artifact derives SectionRef. This lets a diff distinguish a moved
523
+ Section from new content without allowing the same logical Section to have two
524
+ primary placements. The ViewRef is an internal projection. Output paths are
525
+ derived under `knowledge/<collection>/` and never accepted from a Provider.
526
+
527
+ Template Artifacts enter layout only after validated rendering. Only rendered
528
+ Sections exist; an omitted optional projection does not create an empty
529
+ Section, while a retained material gap remains a planned landing without
530
+ reader-visible placeholder content. Artifact Bundle purpose and `split_of`
531
+ lineage are retained in the proposal. A proposal set rejects duplicate Node
532
+ owners, Artifact identities, logical Section identities, Section placements
533
+ and output paths across Indexers, as well as missing, nested or kind-changing
534
+ semantic-split parents.
535
+
536
+ Before Candidate Review, Context builds
537
+ `context.indexer.artifact-manifest/v1` from the current layout set and the
538
+ actual physical Markdown set. The manifest stores paths, content digests,
539
+ byte/body-line counts and exact logical-unit or registered-navigation ownership;
540
+ it does not retain the Markdown body. A separate
541
+ `context.indexer.physical-artifact-audit/v1` recomputes Bundle numerator and
542
+ denominator, per-unit physical fan-out, semantic split count, and the complete
543
+ missing/empty/orphan/unresolved-material sample set. Any such diagnostic is a
544
+ non-overridable completeness failure.
545
+
546
+ Generated navigation must use a content-addressed
547
+ `context.indexer.navigation-artifact-plan/v1`. Nested navigation is allowed,
548
+ but every navigation Artifact must reach a logical-unit Artifact; unknown
549
+ children, cycles, path collisions and unregistered files fail. Reader bodies
550
+ over 1500 lines produce a non-blocking advisory only. Total physical Artifact
551
+ count has no global maximum.
552
+
553
+ An initial layout does not create a structural Gate. A content-only increment
554
+ reuses the existing Artifact identity and also skips the Gate. Adding reader
555
+ fan-out to an already approved Node, removing or renaming an Artifact,
556
+ splitting/merging its declared lineage, moving a logical Section, or changing
557
+ an approved collection/path is represented by a digest-bound layout change
558
+ report and requires the human, non-delegable `confirm-layout-change` Gate.
559
+ `context.indexer.layout-transition/v1` first validates an explicit
560
+ no-planned-output state or a material-answer actualization whose digest and
561
+ actual ArtifactRef/SectionRef all belong to the current proposal set; only
562
+ then does it expose the conditional Gate. Replacing the proposal set makes the
563
+ prior actualization stale. The legacy align Route remains available only until
564
+ the workflow cutover; it is not an authority for the new Indexer protocol.
565
+
566
+ ## Explicit Result-bound Candidate compile
567
+
568
+ `compile-indexer-candidates` consumes the complete current set of accepted
569
+ author Results from the durable main-run store. Its input repeats only the
570
+ exact workset, execution-request, acceptance and Artifact Result digests; the
571
+ CLI rejects a missing, extra, forged or stale Result reference before
572
+ materialization. Callers cannot provide an alternate Result body, Provider
573
+ contract, default plan or prose-compile payload.
574
+
575
+ The compiler validates every accepted run envelope and acceptance record,
576
+ then binds each Candidate to the same Indexer Result, source identity,
577
+ Provider layer and integrity, Bundle digest, configuration fingerprint and
578
+ optional customization fingerprint used by layout. The supplied layout
579
+ proposal set and transition must bind the same Artifact Result set. Any
580
+ destructive layout report additionally requires its exact non-delegable
581
+ confirmation; unresolved material gaps stop compile.
582
+
583
+ Structured Section blocks are materialized directly. Template-backed
584
+ Artifacts use only an exact rendered Artifact bound to the same Result digest.
585
+ The CLI derives physical paths from layout, builds the physical Artifact
586
+ manifest, and requires the completeness audit to pass before returning the
587
+ Candidate set. The durable current record lives under Context runtime state;
588
+ it does not write approved knowledge. Review and apply remain the only route
589
+ to approved Markdown.
590
+
591
+ No generic fallback exists after Provider resolution. A minimal local
592
+ customization may be proposed only after the explicit
593
+ `indexer-customization-required` outcome and its capability-gap proof; compile
594
+ itself never invents one.
595
+
596
+ ## Material-answer dispatch, baseline, Review, and layout actualization
597
+
598
+ `context.indexer.material-question-workset/v1` is built only by the CLI after a
599
+ material-gap checkpoint. It binds the current requirement and registry digests,
600
+ question contract and target inventory, source-input digests, exact question
601
+ revision, predecessor ledger revision, authorized sources, and eligible answer
602
+ Indexers. Eligibility is derived from the registry-enabled `material-answer`
603
+ operation, an enricher binding, the primary Provider manifest, read scope, and
604
+ the evidence-kind intersection; callers cannot add an eligible Indexer.
605
+
606
+ The CLI creates one `context.indexer.run-request/v1` per eligible answer Indexer.
607
+ Its Provider composition fingerprint is recomputed from the answer Indexer,
608
+ exact final Provider authority, and layer-composition view digest. The separate
609
+ material-answer run ledger uses CAS transitions and content-addressed accepted
610
+ records. A complete accepted empty Result is recovered without another dispatch;
611
+ an interrupted running entry without its accepted record returns to pending.
612
+ Before acceptance, every evidence claim must resolve through an exact current
613
+ source-span read receipt, and unused or stale receipts are rejected.
614
+
615
+ A `material-answer` Result cannot move a retained gap directly to an approved
616
+ state. Context first validates the exact workset, question revision, eligible
617
+ Indexer, Provider fingerprint, source authority, canonical spans, evidence
618
+ content digests, provenance selector and minimum item/origin counts. Only a
619
+ passing candidate can produce
620
+ `context.indexer.material-answer-baseline-report/v1`. Its fixed Review scope is
621
+ `question-target-source-span-evidence-binding`; the strict schema has no field
622
+ for approving a reader page, Artifact content or final knowledge candidate.
623
+
624
+ `context.indexer.material-answer-review-decision/v1` binds that report, the
625
+ candidate set, workset, question revision and binding digest. Applying an
626
+ `approved` decision uses the workset's predecessor ledger revision as a CAS
627
+ base, consumes that workset and records the decision digest in the canonical
628
+ answer binding. A successor ledger revision does not make the consumed workset
629
+ self-stale. A rejected, insufficient, forged or differently scoped decision
630
+ cannot create `answer-approved` state.
631
+
632
+ Layout uses an unapplied
633
+ `context.indexer.material-answer-layout-proposal/v1`. Each planned or existing
634
+ answer landing must map uniquely to an actual `node:`, `artifact:` or
635
+ `section:` ref. Before creating a resolved actualization, Context recomputes
636
+ `context.indexer.material-answer-evidence-compatibility/v1` from the retained
637
+ canonical evidence and current question/source authority. A changed source set,
638
+ origin, snapshot, kind, span, content digest, provenance rule or minimum count
639
+ reopens the gap to `unresolved`. A missing or colliding landing remains
640
+ `answer-approved`; rejecting or replacing a layout proposal invalidates its
641
+ resolved mappings back to `answer-approved`.
642
+
643
+ `context.indexer.material-answer-flow-status/v1` is the admission fact for the
644
+ next stages. An unresolved blocking gap stops layout. An `answer-approved`
645
+ blocking gap may enter layout but cannot consume a conditional layout Gate or
646
+ enter the main Candidate Review. Those two admissions become true only when
647
+ every blocking answer has a current actualization for the exact layout digest.
648
+ Optional gaps remain reported but do not become blocking. Final close removes
649
+ a resolved ledger entry only when the approved structure projection carries
650
+ the same question, binding, actualized target and complete canonical evidence
651
+ ref set.
652
+
653
+ ## Detector and inspector
654
+
655
+ An activation detector consumes `context.indexer.activation-request/v1`. The
656
+ request contains the exact declared required, supporting and negative signal
657
+ set plus one `context.indexer.parser-fact-view/v1`. The view is built from
658
+ validated Evidence Adapter Results and their process-local structured fact
659
+ payload sidecars. It binds the authorized source/module scope, canonical file
660
+ inventory, origin Result digests and every payload digest. Raw source or
661
+ configuration text is not part of this input.
662
+
663
+ Parser adapters expose a materialization helper that returns the wire-safe
664
+ `context.indexer.evidence-adapter-result/v1` together with `fact_payloads`.
665
+ Those payloads intentionally do not serialize inside the Result and cannot be
666
+ recovered after a JSON round trip. The caller must construct the parser fact
667
+ view while the sidecar is still present; missing, extra, stale or out-of-view
668
+ payloads fail closed.
669
+
670
+ `context.indexer.activation-result/v1` must close every signal as
671
+ `present`, `absent` or `unknown`; a present signal requires evidence. Context,
672
+ not the detector, derives `matched`, `not-matched` or `indeterminate`.
673
+
674
+ An authoring inspector consumes `context.indexer.inspector-request/v1` and
675
+ returns `context.indexer.inspector-result/v1`. Its evidence payload is the
676
+ shared `context.indexer.evidence-adapter-result/v1`. Inspector files are always
677
+ `enricher` plus `lightweight-evidence`; they cannot own baseline inventory or
678
+ contribute a denominator. The Result must close the requested inventory and
679
+ authorized source/module scope. Detector and inspector entries run only from
680
+ the reverified content-addressed stage through the same empty-environment,
681
+ no-shell, bounded JSON subprocess runner. Timeout, stdin/stdout/stderr overflow,
682
+ invalid UTF-8/JSON, undeclared evidence and scope expansion are typed failures;
683
+ a successful execution returns a digest-bound receipt.
684
+
685
+ ## Project-local customization
686
+
687
+ A Provider-only project does not create `src/indexer/`. When the registry
688
+ explicitly selects `extend` or `replace`, Context reads only
689
+ `src/indexer/<indexer-id>/` and the fixed resources `index.ts`, `variables.ts`,
690
+ `helpers.ts`, `instructions.md` and `templates/<id>.md`. Each file requires an
691
+ exact `@context-indexer-origin` header. `replace` additionally requires a current
692
+ capability-gap proof.
693
+
694
+ Every customization view also carries a validated
695
+ `context.indexer.customization-plan/v1`. The fixed escalation ladder is
696
+ `provider-only`, `config`, `instructions-append`, `template-override`,
697
+ `program-extend`, then `replace`. Selecting a step requires ordered evidence
698
+ that every smaller step is insufficient. `replace` additionally requires three
699
+ distinct failed extension-attempt digests and human confirmation; adding an
700
+ external dependency also makes confirmation mandatory. The selected step must
701
+ match the actual loaded files and the registry's `none | extend | replace`
702
+ mode. A Provider-only workspace gets a deterministic `provider-only` plan and
703
+ must not supply a local escalation plan. A non-empty registry config remains
704
+ registry-only but requires an exact `config` plan with Provider-only closure
705
+ evidence.
706
+
707
+ Project changes are represented by
708
+ `context.indexer.project-proposal/v1`. A proposal binds the unchanged
709
+ requirement-set authority, complete target registry, actual changed files,
710
+ fixed dependency intents, validation reports and expected-base digests. It is
711
+ staged under runtime state before any source write. Applying it uses the project
712
+ write lock and a persistent multi-file journal; recovery accepts only complete
713
+ base or target file states and refuses unknown external drift.
714
+
715
+ Dependency intents begin as `requires-authorization` and cannot make a proposal
716
+ apply-ready. The separate `authorize-indexer-dependencies` Gate requires the
717
+ `context.indexer-dependency-install` authority and binds the proposal, original
718
+ intent-set digest, exact package versions, importers, lock integrity, resolved
719
+ content digests and authority scope. Its CLI Action returns a digest-bound
720
+ authorization receipt plus a new `locked` intent set; install scripts remain
721
+ structurally `false`. A locked intent without its exact receipt, an unused
722
+ receipt, a changed resolution or an ordinary managed authority fails closed.
723
+ The Agent must use that locked set and the complete package/lock snapshots in a
724
+ replacement staged proposal before `apply-indexer-project`; the apply journal
725
+ never writes `node_modules`, which is reconstructed only from the accepted lock.
726
+
727
+ ## Indexer template rendering
728
+
729
+ Indexer authoring templates are not package-output Handlebars templates. Each
730
+ Provider template is one manifest-declared Markdown file under that Provider's
731
+ `templates/` tree. A project may replace only the same template id/profile at
732
+ `src/indexer/<indexer-id>/templates/<id>.md`; all other templates continue to
733
+ come from the verified, content-addressed Provider stage.
734
+
735
+ The Markdown file begins with closed YAML frontmatter using
736
+ `context.indexer.template/v1`. It declares the reader goal, applicable artifact
737
+ policy variants, typed variables with an explicit `deterministic-fact` or
738
+ `semantic-prose` content layer, registered deterministic blocks, required and
739
+ optional Sections, question refs, evidence kinds/cardinality, deletion rules,
740
+ page-boundary guidance, anonymous examples, anti-examples, forbidden output and
741
+ a rendered byte budget. Every body Section uses exact markers:
742
+
743
+ ```md
744
+ <!-- context:indexer-section summary -->
745
+ # {{variable:title}}
746
+
747
+ {{variable:summary}}
748
+ <!-- /context:indexer-section -->
749
+ ```
750
+
751
+ Only `{{variable:<id>}}` and `{{block:<id>}}` are accepted. Direct variables are
752
+ semantic prose. A block source variable is a deterministic Fact projection,
753
+ must bind canonical `fact_refs`, and must equal the CLI's normalized projection
754
+ of those Facts. Blocks select one of
755
+ the CLI-owned `bullet-list`, `key-value-table` or `json-code-block` renderers;
756
+ templates cannot register code or helpers. A block directive occupies its own
757
+ template line so the renderer can retain an exact content-layer boundary. The
758
+ contract and body must declare exactly the same Sections and placeholders.
759
+
760
+ `ArtifactResult` binds every template variable to current evidence refs and
761
+ binds every declared Section to `section_key`, owner Indexer, document kind,
762
+ reader goal and Artifact kind. Rendering validates the Provider/customization
763
+ fingerprints, template digest, current CLI-owned applicability conditions,
764
+ variable types and expansion limits, per-variable evidence boundary and exact
765
+ CLI-owned question target. An optional Section without data
766
+ or sufficient evidence is absent from the rendered Candidate. A required
767
+ Section in the same state becomes the already-declared material-question
768
+ transition and makes `review_ready` false.
769
+
770
+ Before a Candidate can enter Review, Context rejects unknown directives,
771
+ unresolved variables, template comments, example placeholders, standalone or
772
+ bracketed `TODO`/`TBD`/`待补充`/`待生成` markers, title-only Sections and budget
773
+ overflow. A source-backed sentence that discusses a known TODO is not treated
774
+ as a placeholder merely because it contains that token; it remains semantic
775
+ prose and therefore requires Agent Review. The rendered
776
+ Section content, ordered content-layer ledger and evidence receive stable
777
+ digests. Deterministic blocks contribute catalog completeness but never
778
+ semantic-prose density. Later `build` projects this approved body; it does not
779
+ perform a first render or change its structure.
780
+
781
+ An ArtifactResult may emit
782
+ `context.indexer.structured-claim-set/v1`. Every claim binds a stable claim
783
+ kind and subject to one real Artifact/Section owner and one or more evidence
784
+ refs carried by that exact Section. The subject must be the current logical
785
+ unit, one of its CLI-owned inventory members, or an authorized target-resolution
786
+ identity. Missing owners, outside subjects, unknown evidence and evidence that
787
+ is known globally but absent from the owner Section all fail Result validation.
788
+
789
+ Main-run validation derives
790
+ `context.indexer.generated-authoring-audit/v1`. It reports controlled generated
791
+ placeholder and empty emitted-Section hard findings, proves that every emitted
792
+ structured claim passed owner-local evidence coverage, and lists every
793
+ semantic-prose block or direct authored template variable as
794
+ `semantic-prose-agent-review-required`. It does not scan free prose to claim
795
+ that unsupported natural-language assertions were mechanically detected.
796
+
797
+ ## Material-question target exclusion
798
+
799
+ A target exclusion is not a Provider Result and does not change the confirmed
800
+ requirement. Context first emits
801
+ `context.indexer.material-question-exclusion-report/v1` for one current
802
+ unresolved `QuestionTargetKey`. The report binds the project, predecessor
803
+ ledger revision, question-target inventory, question contract and revision,
804
+ target ref/item digest, exact allowlisted reason, derived severity and the
805
+ reader-visible impact.
806
+
807
+ `confirm-material-question-exclusion` accepts only that report and always emits
808
+ `context.indexer.material-question-exclusion-confirmation/v1` with human,
809
+ non-delegable authority. Managed mode, Provider omission, wildcard targets and
810
+ non-allowlisted reasons cannot create the decision. Apply revalidates the
811
+ report against the current resolved question and ledger before retaining only
812
+ the reason code and decision digest in the entry.
813
+
814
+ The successor ledger is checkpointed with the predecessor revision through the
815
+ same durable structure journal. A question contract, owner, target item,
816
+ question revision or other pair dependency change replaces the retained
817
+ exclusion with an unresolved entry in one checkpoint. The Material Gap ledger
818
+ is intentionally absent from the main-workset identity, so this target-level
819
+ decision does not invalidate unrelated main indexing worksets.