agent-doc-system 0.0.0-stage → 1.1.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 (124) hide show
  1. package/INSTALL_FOR_AGENTS.md +60 -0
  2. package/LICENSE +21 -0
  3. package/README.md +98 -2
  4. package/adapters/ansible.mjs +306 -0
  5. package/adapters/cache.mjs +27 -0
  6. package/adapters/contract-consumers.mjs +56 -0
  7. package/adapters/database.mjs +116 -0
  8. package/adapters/deploy-config.mjs +34 -0
  9. package/adapters/dockerfile.mjs +26 -0
  10. package/adapters/events.mjs +145 -0
  11. package/adapters/generic.mjs +86 -0
  12. package/adapters/github-actions.mjs +106 -0
  13. package/adapters/go.mjs +91 -0
  14. package/adapters/graphql.mjs +28 -0
  15. package/adapters/index.mjs +56 -0
  16. package/adapters/node.mjs +118 -0
  17. package/adapters/object-store.mjs +64 -0
  18. package/adapters/oidc.mjs +56 -0
  19. package/adapters/openapi.mjs +50 -0
  20. package/adapters/pnpm.mjs +42 -0
  21. package/adapters/protobuf.mjs +35 -0
  22. package/adapters/registry.mjs +27 -0
  23. package/adapters/resource-client.mjs +61 -0
  24. package/adapters/turborepo.mjs +135 -0
  25. package/adapters/typescript.mjs +85 -0
  26. package/adapters/wrangler.mjs +206 -0
  27. package/bin/agentdoc.mjs +494 -0
  28. package/bin/commands.mjs +169 -0
  29. package/bin/usage.txt +28 -0
  30. package/core/acceptances.mjs +69 -0
  31. package/core/audit.mjs +456 -0
  32. package/core/authority/classes.mjs +39 -0
  33. package/core/authority/engine.mjs +266 -0
  34. package/core/authority/facts.mjs +41 -0
  35. package/core/codes.mjs +126 -0
  36. package/core/compile.mjs +1018 -0
  37. package/core/contracts.mjs +121 -0
  38. package/core/derive.mjs +102 -0
  39. package/core/descriptors.mjs +489 -0
  40. package/core/determinism.mjs +95 -0
  41. package/core/discover.mjs +147 -0
  42. package/core/facts.mjs +53 -0
  43. package/core/fsx.mjs +348 -0
  44. package/core/graph.mjs +260 -0
  45. package/core/impact.mjs +175 -0
  46. package/core/indexes.mjs +165 -0
  47. package/core/jsonschema.mjs +298 -0
  48. package/core/normative.mjs +171 -0
  49. package/core/observations.mjs +129 -0
  50. package/core/provenance.mjs +83 -0
  51. package/core/query.mjs +384 -0
  52. package/core/relations.mjs +286 -0
  53. package/core/scaffold.mjs +322 -0
  54. package/core/secrets.mjs +92 -0
  55. package/core/sourcescan.mjs +88 -0
  56. package/core/toml.mjs +163 -0
  57. package/core/yaml.mjs +477 -0
  58. package/docs/ADAPTERS.md +207 -0
  59. package/docs/AUTHORITY.md +269 -0
  60. package/docs/CI.md +138 -0
  61. package/docs/COMPARISON-KODA.md +164 -0
  62. package/docs/EVALS.md +166 -0
  63. package/docs/MIGRATION.md +261 -0
  64. package/docs/PROVENANCE.md +133 -0
  65. package/docs/QUERY.md +180 -0
  66. package/docs/SPEC.md +339 -0
  67. package/docs/VERIFICATION.md +28 -0
  68. package/docs/assets/readme/agentdoc-hero.webp +0 -0
  69. package/docs/assets/readme/agentdoc-in-action.webp +0 -0
  70. package/docs/assets/readme/how-agentdoc-works.webp +0 -0
  71. package/docs/assets/readme/why-agentdoc.webp +0 -0
  72. package/docs/ci/generic-ci.sh +28 -0
  73. package/docs/ci/github-actions.yml +35 -0
  74. package/evals/harness.mjs +426 -0
  75. package/evals/scenarios/fixture-a-01-change-api.json +9 -0
  76. package/evals/scenarios/fixture-a-02-change-db.json +9 -0
  77. package/evals/scenarios/fixture-a-03-enforce-constraint.json +9 -0
  78. package/evals/scenarios/fixture-b-01-change-proto.json +9 -0
  79. package/evals/scenarios/fixture-b-02-change-write-path.json +9 -0
  80. package/evals/scenarios/fixture-b-03-change-shared-lib.json +9 -0
  81. package/evals/scenarios/fixture-b-04-journey.json +9 -0
  82. package/evals/scenarios/fixture-c-01-mixed-runtime-edge.json +19 -0
  83. package/evals/scenarios/fixture-c-02-stale-doc-contradiction.json +9 -0
  84. package/evals/scenarios/fixture-c-03-shared-vocabulary.json +9 -0
  85. package/evals/scenarios/fixture-c-04-contract-change.json +9 -0
  86. package/evals/scenarios/koda-01-modify-api-consumer.json +26 -0
  87. package/evals/scenarios/koda-02-change-db-schema.json +20 -0
  88. package/evals/scenarios/koda-03-change-auth.json +21 -0
  89. package/evals/scenarios/koda-04-add-event-producer.json +19 -0
  90. package/evals/scenarios/koda-05-modify-worker-binding.json +25 -0
  91. package/evals/scenarios/koda-06-change-cross-component-endpoint.json +22 -0
  92. package/evals/scenarios/koda-07-change-shared-package.json +16 -0
  93. package/evals/scenarios/koda-08-change-runtime-cron.json +23 -0
  94. package/evals/scenarios/koda-09-debug-production-mismatch.json +26 -0
  95. package/evals/thresholds.json +11 -0
  96. package/package.json +46 -4
  97. package/schemas/api.schema.json +84 -0
  98. package/schemas/common.schema.json +147 -0
  99. package/schemas/component.schema.json +44 -0
  100. package/schemas/config.schema.json +801 -0
  101. package/schemas/domain.schema.json +14 -0
  102. package/schemas/graph.schema.json +1084 -0
  103. package/schemas/journeys.schema.json +47 -0
  104. package/schemas/observation.schema.json +143 -0
  105. package/schemas/resource.schema.json +28 -0
  106. package/schemas/system.schema.json +26 -0
  107. package/skills/agent-doc-system/SKILL.md +117 -0
  108. package/skills/agent-doc-system/references/authority-and-conflicts.md +70 -0
  109. package/skills/agent-doc-system/references/cli.md +97 -0
  110. package/skills/agent-doc-system/references/create-migrate.md +113 -0
  111. package/skills/agent-doc-system/references/maintenance.md +52 -0
  112. package/templates/ADR.md +26 -0
  113. package/templates/ARCHITECTURE.md +19 -0
  114. package/templates/CONSTRAINTS.md +17 -0
  115. package/templates/PRODUCT.md +17 -0
  116. package/templates/api.yaml +10 -0
  117. package/templates/ci.yml +31 -0
  118. package/templates/component.yaml +14 -0
  119. package/templates/domain.yaml +6 -0
  120. package/templates/journey.yaml +7 -0
  121. package/templates/observation.yaml +19 -0
  122. package/templates/resource.yaml +8 -0
  123. package/templates/system.yaml +10 -0
  124. package/templates/warning-acceptance.yaml +14 -0
package/docs/EVALS.md ADDED
@@ -0,0 +1,166 @@
1
+ # EVALS
2
+
3
+ Does routing an agent through this system retrieve the *right* context, and less
4
+ noise than exploring the repository unaided?
5
+
6
+ ## What is measured
7
+
8
+ The question is not "does it compile". A catalog can compile perfectly and still
9
+ route an agent into the wrong corner of the repository. The measurement is
10
+ retrieval quality, on the same scenarios, for two retrieval systems.
11
+
12
+ **baseline-targeted** — what an agent that has no catalog and looks only where
13
+ the change is: the touched component, its subtree, its relations, its documents
14
+ and its checks.
15
+
16
+ **baseline-full** — what an agent with no routing ends up holding: every entity,
17
+ every relation, every event subject, every check, every document in the
18
+ repository. This is the honest cost of "just read the repository", and it is the
19
+ size yardstick for reduction.
20
+
21
+ **catalog** — what `agentdoc query` returns for the touched paths, plus the
22
+ context of the components `impact` says are affected.
23
+
24
+ No model is involved. Retrieval sets are compared as sets, so the measurement
25
+ is deterministic and cannot be moved by phrasing.
26
+
27
+ ## Metrics
28
+
29
+ | metric | definition |
30
+ |---|---|
31
+ | recall | fraction of the scenario's ground-truth facts the catalog retrieved |
32
+ | critical recall | the same, restricted to critical context: constraints, conflicts, observations, resources, API boundaries, event subjects |
33
+ | verification recall | fraction of the checks that must be run, that were returned |
34
+ | precision | `1 - irrelevance` |
35
+ | irrelevance (noise) | fraction of retrieved facts outside the graph's one-hop closure of the touched entities |
36
+ | retrieval reduction | `1 - catalog facts / baseline-full facts` |
37
+
38
+ ### Why noise is measured against reachability, not against the truth set
39
+
40
+ The first definition of noise was the complement of truth recall. It is
41
+ degenerate: a scenario lists the handful of facts that matter, so any
42
+ *additional legitimate* fact — a sibling constraint, a second check, an adjacent
43
+ contract — is scored as noise. The metric rewarded returning almost nothing.
44
+
45
+ It was replaced, before any repository other than the golden corpus was
46
+ measured, with a question that does not depend on the truth set at all:
47
+
48
+ > did routing drag in anything the graph itself says is unrelated?
49
+
50
+ Relevance is the **one-hop** graph closure of the touched entities, computed
51
+ from the compiled graph. The metric therefore cannot be satisfied by inflating a
52
+ truth set, and it is not satisfied by returning less either — that shows up as
53
+ recall. Recall is still measured against the truth sets, unchanged.
54
+
55
+ "One hop" is load-bearing and is enforced. An earlier implementation took the
56
+ transitive closure, which on the golden corpus grows to nearly the whole
57
+ repository; a router that returned *every fact in the repository* then scored as
58
+ precise, because everything was technically adjacent to something. The metric
59
+ was measuring its own closure, not the router.
60
+
61
+ ## Thresholds
62
+
63
+ Pre-registered in `evals/thresholds.json`, dated, and not moved since:
64
+
65
+ ```json
66
+ { "minRecall": 0.9, "minCriticalRecall": 0.95, "minVerificationRecall": 0.8,
67
+ "minPrecision": 0.75, "maxNoise": 0.6, "minRetrievalReduction": 0.4,
68
+ "minRecallOverBaseline": 0.9 }
69
+ ```
70
+
71
+ Two additional gates use the same numbers:
72
+
73
+ - **recall must not be worse than baseline-targeted.** A catalog that retrieves
74
+ less than reading the component would be worthless.
75
+ - **recall must be at least 0.9 × baseline-full recall.** Routing must not be
76
+ meaningfully worse than reading everything.
77
+
78
+ ### Where the gate is applied
79
+
80
+ - **Aggregate** (`node evals/run-all.mjs`) applies every threshold,
81
+ **and fails if any single corpus fails or is missing**. A corpus that is
82
+ missing fails the gate outright: silently scoring three repositories and
83
+ reporting PASS would be a gate that shrinks when the system shrinks. The two
84
+ relative-baseline checks are evaluated per corpus and folded into the
85
+ aggregate's failure list; the aggregate does not re-derive them, so they are
86
+ lost if a corpus never runs — which is why a missing corpus is itself a
87
+ failure. A per-corpus failure is folded into the aggregate exit
88
+ code, so a broken fixture cannot print FAIL and still exit 0. This is the
89
+ system-level claim.
90
+ - **Per repository** (`agentdoc eval routing`) applies every threshold except
91
+ retrieval reduction, which is reported as *not measured* when the whole-repo
92
+ baseline holds fewer than 100 facts. A one-component repository has almost
93
+ nothing to route away from; failing it would be punishing the fixture for
94
+ being small. The floor and the reasoning are in `evals/harness.mjs`.
95
+
96
+ ## Corpora and scenarios
97
+
98
+ | corpus | scenarios | what it proves |
99
+ |---|---|---|
100
+ | `examples/koda` (golden corpus) | 9 | monorepo discovery, TypeScript + Go, `apps`/`packages`/`workers`, OpenAPI, OIDC, runtime calls, resources, events, verification, journeys, warning acceptances, authority conflicts |
101
+ | `fixtures/a-node-ts-postgres` | 3 | single Node/TypeScript service, REST, Postgres, GitHub Actions |
102
+ | `fixtures/b-go-multi-service` | 4 | multi-service Go, protobuf contracts, shared library, resources |
103
+ | `fixtures/c-alt-monorepo` | 4 | a layout that is deliberately not `apps`+`packages`+`workers`, mixed runtimes, inconsistent pre-existing documentation |
104
+
105
+ Scenarios are repository-scoped: a scenario only runs against the corpus it was
106
+ written for, declared by a `repository` tag in a `.agentdoc-fixture.json` at the
107
+ repository root. Expectations from one fixture can never leak into another's
108
+ score.
109
+
110
+ ### Scenario families
111
+
112
+ The golden corpus covers, in order: modify one API consumer; change a database
113
+ schema; change authentication; add an event producer; modify a worker binding;
114
+ change a cross-component endpoint; change a shared package; change a runtime
115
+ cron; debug a production mismatch.
116
+
117
+ The synthetic fixtures add: change an API contract; change a write path; change
118
+ the only-writer rule; break an end-to-end journey; change an edge worker's flush
119
+ schedule; follow stale documentation while debugging; change a subject vocabulary
120
+ shared across runtimes; add an operation to a contract.
121
+
122
+ ## Running it
123
+
124
+ ```bash
125
+ agentdoc eval routing --json # one repository (from a corpus directory)
126
+ node evals/run-all.mjs # aggregate gate — source checkout only
127
+ node evals/run-all.mjs --json # machine-readable
128
+ ```
129
+
130
+ `run-all.mjs` iterates the corpora in `fixtures/` and `examples/`, so it only
131
+ exists in a source checkout; it is not part of the installed CLI's job.
132
+
133
+ ## What the evaluation changed
134
+
135
+ The evaluation is a tool, not a ceremony. Running it against the golden corpus
136
+ exposed real defects that no unit test had:
137
+
138
+ - contract files did not route (changing an endpoint resolved to nothing);
139
+ - a scheduled trigger did not resolve to the component serving the target route,
140
+ so "who does this cron call?" had no answer;
141
+ - event subjects defined in a shared package were not credited to the component
142
+ that published them;
143
+ - a documentation file linked by a descriptor did not route to its component, so
144
+ stale documentation was unreachable — precisely the migration case;
145
+ - the noise metric was degenerate (above), and the `transitiveClosure` variant
146
+ that replaced it briefly was worse;
147
+ - migration directories were matched by a fixed list of framework conventions
148
+ rather than by the stable fact that the directory is called `migrations`;
149
+ - cross-unit resolution depended on adapter execution order;
150
+ - a repository path was resolved against the process working directory, so the
151
+ same commit compiled differently depending on where the compiler ran.
152
+
153
+ Each was fixed in the engine, not by relaxing a threshold.
154
+
155
+ ## Honest limitations
156
+
157
+ - Ground truth is hand-authored per scenario. It is written from the
158
+ repository's own manifests and contracts, not from the system's output, but it
159
+ is still a human judgement about what matters.
160
+ - The baseline is a model of unassisted exploration, not a record of a real
161
+ agent session. It is generous to the baseline by construction (baseline-full
162
+ is everything), which makes the reduction claim conservative.
163
+ - `retrievalReduction` is a fact-count proxy, not a token count. It does not
164
+ weight a long constraint file against a short ref.
165
+ - Scenarios touch one or two files. A change spanning twenty files is not
166
+ measured.
@@ -0,0 +1,261 @@
1
+ # MIGRATION
2
+
3
+ Two workflows. CREATE for a repository with no catalog; MIGRATE for an
4
+ established one. Both start with the same audit; MIGRATE adds a source-of-truth
5
+ mapping and a reviewed-ambiguity list that a human must work through.
6
+
7
+ ## Choosing
8
+
9
+ | situation | mode |
10
+ |---|---|
11
+ | no `agentdoc/` directory, small or new repository | CREATE |
12
+ | no `agentdoc/`, large or established repository | MIGRATE |
13
+ | an existing catalog, documentation that has drifted | MIGRATE |
14
+ | a catalog that is stale but structurally sound | MAINTAIN |
15
+
16
+ The test is not size. It is whether the repository has documentation that
17
+ *claims* things. Claims need verifying; that is migration work regardless of how
18
+ few components there are.
19
+
20
+ ## The audit
21
+
22
+ ```bash
23
+ agentdoc audit
24
+ ```
25
+
26
+ `audit` runs even when the repository cannot compile, and reports compilation
27
+ failures as part of the report. It inventories four sources of truth
28
+ independently:
29
+
30
+ 1. **manifests and code** — what can be derived;
31
+ 2. **machine-readable contracts** — what boundaries are declared;
32
+ 3. **authored documentation** — what someone believed;
33
+ 4. **authoritative external systems** — what is deployed, via ObservationSets.
34
+
35
+ ## The report
36
+
37
+ ```json
38
+ {
39
+ "inventory": { "files", "units", "entities", "components", "apis", "relations", "contracts", "documentationFiles", "observations", "verification" },
40
+ "facts": [ { "fact": "component:default/teacher placement.system", "classification": "DERIVED", "evidence": ["authored"] } ],
41
+ "counts": { "CONFIRMED": 4, "DERIVED": 38 },
42
+ "contradictions": [ ... ],
43
+ "documentationContradictions": [ ... ],
44
+ "normative": { "sections": [ { "path", "section", "heading", "sha256", "coveredBy" } ], "uncovered": [ ... ], "requirements": [ ... ] },
45
+ "reviewedAmbiguity": [ ... ],
46
+ "documentation": { "orphanDocs", "undocumentedComponents", "unverifiedComponents" },
47
+ "contracts": { "inventory", "unclaimed" },
48
+ "observations": [ { "id", "capturedAt", "maxAgeDays", "environment" } ],
49
+ "scaffold": { "files", "summary", "rule" }
50
+ }
51
+ ```
52
+
53
+ ### Classification
54
+
55
+ Every major fact lands in exactly one class:
56
+
57
+ | class | meaning | may be authored? |
58
+ |---|---|---|
59
+ | `CONFIRMED` | two or more independent sources agree | yes |
60
+ | `DERIVED` | deterministically derivable from the repository | yes, once reviewed |
61
+ | `OBSERVED` | read from an authoritative external system | **no** — it belongs in an ObservationSet |
62
+ | `CONFLICT` | sources disagree and no authority rule settles it | **no** — needs a human |
63
+ | `UNRESOLVED` | neither the repository nor an external system answers it | **no** — needs a human |
64
+
65
+ **Uncertainty is never promoted to authored truth.** This is the rule the whole
66
+ report exists to enforce.
67
+
68
+ ### Documentation contradictions
69
+
70
+ Two checks run against claims the graph actually owns, and only those. A document
71
+ saying "we use Kafka" is not checkable until a Resource descriptor says what the
72
+ Kafka thing is; a document saying "there is no edge component" is checkable
73
+ immediately, and is `NEGATED_COMPONENT`. A port claim in a document linked to a
74
+ component is `PORT_MISMATCH` when the source binds a different port, and
75
+ `UNLINKED_PORT_CLAIM` when the document is linked to nothing and therefore cannot
76
+ be checked at all.
77
+
78
+ The rule for extending this: only check vocabulary the graph owns. A check that
79
+ guesses is a check that cries wolf.
80
+
81
+ **These are the only automatic documentation checks.** The audit does not read
82
+ prose for meaning, so it does not find where an arbitrary sentence contradicts
83
+ the code. A specification saying "the verifier runtime is installed on the
84
+ production host" is invisible to it until someone turns that sentence into a
85
+ requirement — which is what the next section makes mandatory.
86
+
87
+ ### Normative requirements
88
+
89
+ A specification that is linked to a component is *routed*; that says nothing
90
+ about whether anyone checked the implementation against it. List the documents
91
+ that state obligations in `docs.normative`:
92
+
93
+ ```yaml
94
+ docs:
95
+ normative:
96
+ - specs/**
97
+ - verification_layer/*_PROFILE.md
98
+ ```
99
+
100
+ Every level-2 (`##`) section of those documents is then pinned by digest and
101
+ must be accounted for in one of two ways:
102
+
103
+ - **a requirement** on the component that must fulfil it, citing the section:
104
+
105
+ ```yaml
106
+ # provisioning/agentdoc.yaml
107
+ spec:
108
+ requirements:
109
+ - id: verification-runtime-on-host
110
+ key: requirement.provides.verification-runtime
111
+ value: provided
112
+ source:
113
+ path: specs/EXECUTION_LAYER_SPEC.md
114
+ section: 13-host-configuration
115
+ sha256: <digest from `agentdoc audit` → normative.sections>
116
+ satisfiedBy: [ansible]
117
+ expects:
118
+ installs: /var/lib/agent-platform-runtime/verification-python-v1
119
+ ```
120
+
121
+ - **an attestation** in `normativeCoverage` that the section carries no
122
+ implementation obligation (`disposition: no-implementation-obligation` or
123
+ `informative`), with a reason and a review condition.
124
+
125
+ A section that is neither raises `AGENTDOC_NORMATIVE_UNCOVERED`. A requirement
126
+ is an `AUTHORED` fact that can only be *corroborated*: until implementation
127
+ evidence on the same key agrees with it — a `DERIVED` fact from an adapter
128
+ named in `satisfiedBy` that finds what `expects` names (see `ADAPTERS.md`,
129
+ `ansible`), or a
130
+ `requirement-satisfaction` reviewed override citing the implementation — it is
131
+ `UNRESOLVED` and raises `AGENTDOC_REQUIREMENT_UNVERIFIED`, naming the adapter in
132
+ `satisfiedBy` that is missing. Implementation evidence that disagrees is a
133
+ conflict no authority rule may settle (see `AUTHORITY.md`). Editing a cited
134
+ section invalidates its requirement or attestation
135
+ (`AGENTDOC_NORMATIVE_SOURCE_STALE`): the review has to be redone.
136
+
137
+ A missing adapter lowers coverage; it never makes an obligation disappear.
138
+
139
+ ### Reviewed ambiguity
140
+
141
+ The list a human must work through:
142
+
143
+ | kind | what a human decides |
144
+ |---|---|
145
+ | `EVENT_WITHOUT_PRODUCER` | is this subject reserved, or is a producer missing? |
146
+ | `COMPONENT_OWNERSHIP` | which system or domain owns this? |
147
+ | `UNCLAIMED_CONTRACT` | which API owns this contract, or is it dead? |
148
+ | `REVIEWED_OVERRIDE` | is this interpretation still true? |
149
+ | `NEGATED_COMPONENT`, `PORT_MISMATCH`, `UNLINKED_PORT_CLAIM` | which source is right? |
150
+ | `NORMATIVE_UNCOVERED` | what does this section oblige, and which component must do it? |
151
+ | `REQUIREMENT_UNVERIFIED` | where is the implementation — or is this a gap to fix before release? |
152
+
153
+ ## CREATE
154
+
155
+ ```bash
156
+ agentdoc init # configuration + doc skeleton
157
+ $EDITOR agentdoc/agentdoc.config.yaml # layout, namespace, adapters
158
+ agentdoc audit # what is provable
159
+ agentdoc scaffold --write
160
+ $EDITOR '**/agentdoc.yaml' # every generated description
161
+ agentdoc validate
162
+ agentdoc compile
163
+ agentdoc check
164
+ ```
165
+
166
+ `init` writes `agentdoc/agentdoc.config.yaml`, the four central descriptor
167
+ files, `agentdoc/journeys.yaml`, the documentation hierarchy
168
+ (`docs/PRODUCT.md`, `docs/ARCHITECTURE.md`, `docs/CONSTRAINTS.md`,
169
+ `docs/adr/`), the observations README, and a CI workflow. It never overwrites an
170
+ existing file.
171
+
172
+ `scaffold` is a dry run unless `--write` is passed.
173
+
174
+ ### What the scaffolder will and will not do
175
+
176
+ It writes a component descriptor only for a unit it can name from the
177
+ repository — a package name, a module path, or a directory name. It writes a
178
+ description that is a template sentence naming the artifact evidence. It does
179
+ **not** choose a system or a domain, because placement is an ownership decision
180
+ no extractor can make; the generated descriptor carries a commented
181
+ `placementRationale` prompt instead.
182
+
183
+ That is deliberate. A scaffolder that guesses ownership produces a catalog
184
+ nobody trusts.
185
+
186
+ ## MIGRATE
187
+
188
+ ```bash
189
+ agentdoc init
190
+ # set componentDescriptors to the real layout; enable the right adapters
191
+ agentdoc audit > migration-report.json
192
+ ```
193
+
194
+ Then, in order:
195
+
196
+ 1. **Source-of-truth mapping.** Configure `docs.normative`, then work
197
+ `normative.uncovered`: every section of every normative document becomes a
198
+ component requirement or a reviewed attestation. Prove each requirement
199
+ with implementation evidence, or leave it `REQUIREMENT_UNVERIFIED` for a
200
+ human. For other major claims, record which of the four inventories
201
+ supports them; anything supported by none goes to `reviewedAmbiguity`.
202
+ 2. **Contradiction detection.** Work `contradictions` and
203
+ `documentationContradictions`. Each one needs a human decision: fix the
204
+ documentation, fix the code, or record an authority rule saying which class
205
+ wins for that key.
206
+ 3. **Orphan documentation.** `documentation.orphanDocs`. For each: link it to a
207
+ component via `context.docs`, or delete it. An orphan is a document nothing
208
+ will ever route to.
209
+ 4. **Missing documentation.** `documentation.undocumentedComponents` and
210
+ `documentation.unverifiedComponents`. These are the components an agent will
211
+ get wrong.
212
+ 5. **Stale contracts.** `contracts.unclaimed`, and any contract whose consumers
213
+ changed. Point the API descriptor at the current file; do not duplicate it.
214
+ 6. **Ownership reconstruction.** Placement comes from the code where the code is
215
+ unambiguous (a service that only ever talks to one identity provider), and
216
+ from a human everywhere else.
217
+ 7. **Catalog proposal.** `scaffold` lists what it would write.
218
+ 8. **Migration.** `scaffold --write`, then review every generated file.
219
+ 9. **Validation.** `validate` → `compile` → `check --strict`. The strict gate
220
+ fails on every warning not accepted with pinned evidence, so a migration
221
+ cannot finish with an unreviewed normative section or an unproven
222
+ requirement. A known gap is accepted explicitly (`warningAcceptances`) and
223
+ stays `UNRESOLVED` in the audit.
224
+
225
+ ### Do not trust the documentation
226
+
227
+ The single most common migration failure is copying existing prose into
228
+ descriptions. The audit exists to find out how much of that prose is still true.
229
+ A description is a one-sentence present-tense statement of current purpose; if
230
+ you cannot write one, the component's purpose is not understood yet, and that is
231
+ worth discovering before documenting it.
232
+
233
+ ## Documentation hierarchy
234
+
235
+ | kind | belongs there | must not |
236
+ |---|---|---|
237
+ | `PRODUCT.md` | what it is, for whom, what it does not do | describe components |
238
+ | `ARCHITECTURE.md` | why the shape is what it is | enumerate components or contracts |
239
+ | `CONSTRAINTS.md` | repository-wide rules, one rule one reason one check | restate a component's constraints |
240
+ | `docs/adr/NNNN-*.md` | one decision, its consequences, superseded not edited | be a design document |
241
+ | `<component>/CONSTRAINTS.md` | rules for that component only | duplicate a repository-wide rule |
242
+ | `<component>/README.md` | how to run it, what it is for | restate the catalog |
243
+ | runbooks | operational procedure | contain architectural decisions |
244
+ | `agentdoc/observations/` | what a live system said, with evidence | contain credentials |
245
+ | the graph | topology, contracts, events, checks, conflicts | contain prose |
246
+
247
+ **The duplication rule.** A fact lives in exactly one place. Elsewhere, point at
248
+ it. If `ARCHITECTURE.md` lists the components, it will be wrong within a month,
249
+ and `agentdoc query` will be right. The architecture document explains *why*;
250
+ the graph says *what*.
251
+
252
+ ## Finishing
253
+
254
+ ```bash
255
+ agentdoc validate && agentdoc check
256
+ agentdoc eval routing
257
+ git add -A && git commit
258
+ ```
259
+
260
+ Then install CI (`CI.md`) so the next drift is caught by a gate rather than by a
261
+ review.
@@ -0,0 +1,133 @@
1
+ # PROVENANCE
2
+
3
+ Every important fact in the compiled graph is traceable to evidence. This
4
+ document defines what a provenance record is, how it is produced, and the rules
5
+ that keep evidence free of secrets.
6
+
7
+ ## The record
8
+
9
+ ```json
10
+ {
11
+ "id": "p-0075",
12
+ "class": "observed",
13
+ "path": "workers/koda-cron/wrangler.toml",
14
+ "extractor": { "name": "platform-manifest-extractor", "version": "1.0.0" },
15
+ "contentHash": "sha256:9f2c...",
16
+ "location": { "lineStart": 5, "lineEnd": 7, "jsonPointer": "/facts/2" },
17
+ "subjects": ["/entities/9/derived/bindings/0", "/conflicts/2"]
18
+ }
19
+ ```
20
+
21
+ | field | meaning |
22
+ |---|---|
23
+ | `id` | positional over a canonical sort, so ids are stable for a given input set |
24
+ | `class` | how the evidence was obtained (below) |
25
+ | `path` | repository-relative; never absolute, never outside the checkout |
26
+ | `extractor` | which component read it, and at what version |
27
+ | `contentHash` | `sha256:` of the file bytes as read |
28
+ | `location` | optional: line range or JSON pointer, when the evidence is narrower than the file |
29
+ | `subjects` | RFC 6901 pointers into this graph that the record proves |
30
+
31
+ ## Classes
32
+
33
+ | class | meaning | typical extractor |
34
+ |---|---|---|
35
+ | `declared` | the file states the fact outright | `descriptor-reader`, `placement-extractor` |
36
+ | `reviewed` | a human interpretation recorded in configuration, not derivable from a file | `override-extractor` |
37
+ | `observed` | the file shows the fact | `manifest-extractor`, `import-extractor`, `ci-extractor` |
38
+ | `validated` | two independent files agree | `api-contract-extractor`, `oidc-extractor` |
39
+ | `runtime` | read from an external system | `observation:<collector>` |
40
+ | `standard` | the authority is a published standard | `standard-extractor` |
41
+
42
+ `runtime` records are the only ones whose path is not a source file of the
43
+ repository under analysis in the ordinary sense: they point at the committed
44
+ evidence bundle the observation cites.
45
+
46
+ `reviewed` exists so that a human interpretation is not filed as `declared`.
47
+ Filed that way it mapped to `AUTHORED` — the strongest class — so a reviewed
48
+ override corroborated by a source reference was relabelled `AUTHORED` on the
49
+ merged edge, and the graph understated its own highest-authority input. The class
50
+ is not an election either: elections happen per fact in the authority model, and a
51
+ provenance class must not decide one on its own.
52
+
53
+ ## Coverage rules
54
+
55
+ - Every relation, external dependency, capability, verification entry, gate,
56
+ journey, contract, conflict and assertion carries at least one
57
+ `provenanceIds` entry.
58
+ - Every entity carries provenance for its authored fields and, for components,
59
+ for its derived block.
60
+ - A relation, index entry or fact with no provenance is a compiler defect. The
61
+ pipeline fails with `AGENTDOC_PROVENANCE` rather than emitting it.
62
+
63
+ ## Subject resolution
64
+
65
+ Extractors emit symbolic subjects while they run (`rel:pending`,
66
+ `ass:pending`, `evt:<pattern>`, …) and the compiler binds them to concrete
67
+ pointers once the whole graph exists. This is why an extractor's output does not
68
+ depend on how many other extractors ran first.
69
+
70
+ A subject that never binds is an error: `AGENTDOC_PROVENANCE`. The single
71
+ exception is evidence whose candidate edge or fact was *dropped* (an unresolved
72
+ reviewed override, a rejected candidate). Those records are removed and the
73
+ count is reported as `droppedProvenance` in the compile stats, so a regression
74
+ here is visible rather than silent.
75
+
76
+ ## Input hashing
77
+
78
+ `source.inputHash` covers:
79
+
80
+ 1. compiler and graph-schema versions, entity api version, authority-rule count,
81
+ every enabled adapter's name and version, and the content hash of every
82
+ shipped schema;
83
+ 2. every file the compiler read — path and content, length-prefixed;
84
+ 3. every existence probe — path and result;
85
+ 4. every directory listing — directory and sorted file list.
86
+
87
+ Every byte the compiler reads flows through a single tracked read path, so the
88
+ record is complete by construction rather than by remembering to register files.
89
+ A change to any input changes the hash; `check` refuses a graph whose hash
90
+ disagrees.
91
+
92
+ ## Secrets
93
+
94
+ Two independent layers, because derivation can synthesise a secret-shaped string
95
+ that no source scan would have caught.
96
+
97
+ **Layer 1 — sources.** Every authored or observed document is scanned before it
98
+ can influence any output. Refusal is `AGENTDOC_SECRET`, with the JSON pointer.
99
+
100
+ **Layer 2 — outputs.** The serialized graph, every audit report, every query
101
+ payload and every eval report is scanned again before it is written or printed.
102
+ Refusal is `AGENTDOC_SECRET` and the command exits non-zero. Nothing is written
103
+ partially.
104
+
105
+ Detected shapes include private-key headers, cloud access-key ids, provider
106
+ token prefixes, JWT-shaped triples, URLs with embedded credentials, `Bearer`
107
+ tokens, and `secret: value` / `token = value` style assignments.
108
+
109
+ **Commands are redacted, not dropped.** A verification command is a routing
110
+ index, not a credential transport. An inline assignment whose name contains
111
+ `SECRET`, `TOKEN`, `PASSWORD`, `PASSPHRASE`, `API_KEY`, `PRIVATE_KEY`,
112
+ `CREDENTIAL` or `ACCESS_KEY` keeps its name and loses its value:
113
+
114
+ ```
115
+ DATABASE_URL=postgres://u:p@host/db vitest run
116
+ -> DATABASE_URL=[REDACTED] vitest run
117
+ ```
118
+
119
+ The redaction marker itself is not treated as a secret, so a redacted command
120
+ remains runnable and printable.
121
+
122
+ **Observations.** An `evidenceBundle` must be a committed, repository-relative
123
+ file. A temp path, a console URL with a session token, or a screenshot filename
124
+ is not evidence. The environment identifier is constrained to a slug; nothing in
125
+ an observation may be a credential.
126
+
127
+ ## What is deliberately not provenance
128
+
129
+ - **Confidence.** A heuristic derivation is still traceable; `confidence:
130
+ candidate` says it may not be elected. Provenance and confidence answer
131
+ different questions.
132
+ - **Ownership.** Placement is an authored fact with a `declared` record, not a
133
+ derived one. The extractor identity tells you who read it, not who decided it.