prompt-linker 0.8.0__tar.gz

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 (52) hide show
  1. prompt_linker-0.8.0/.gitignore +40 -0
  2. prompt_linker-0.8.0/CHANGELOG.md +94 -0
  3. prompt_linker-0.8.0/Docs/Commands.md +105 -0
  4. prompt_linker-0.8.0/Docs/Errors.md +112 -0
  5. prompt_linker-0.8.0/Docs/PromptLinker.md +461 -0
  6. prompt_linker-0.8.0/Docs/Verification.md +207 -0
  7. prompt_linker-0.8.0/Examples/StarterTemplate/Linker.yaml +14 -0
  8. prompt_linker-0.8.0/Examples/StarterTemplate/README.md +22 -0
  9. prompt_linker-0.8.0/Examples/StarterTemplate/contracts/greeting-style/contract.md +9 -0
  10. prompt_linker-0.8.0/Examples/StarterTemplate/contracts/greeting-style/friendly.md +5 -0
  11. prompt_linker-0.8.0/Examples/StarterTemplate/contracts/greeting-style/terse.md +5 -0
  12. prompt_linker-0.8.0/Examples/StarterTemplate/skeletons/example-skill/instructions.md +13 -0
  13. prompt_linker-0.8.0/Examples/StarterTemplate/skeletons/example-skill/reference.md +4 -0
  14. prompt_linker-0.8.0/Examples/TestConfiguration/Linker.yaml +39 -0
  15. prompt_linker-0.8.0/Examples/TestConfiguration/README.md +20 -0
  16. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/continuation/contract.md +10 -0
  17. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/continuation/spawn-next.md +7 -0
  18. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/continuation/stop.md +6 -0
  19. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/finding-routing/contract.md +8 -0
  20. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/finding-routing/local.md +6 -0
  21. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/finding-routing/tracker.md +8 -0
  22. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/freshness-substrate/contract.md +8 -0
  23. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/freshness-substrate/projection.md +8 -0
  24. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/freshness-substrate/writethrough.md +7 -0
  25. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/knowledge-integration/contract.md +9 -0
  26. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/knowledge-integration/deferred.md +8 -0
  27. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/knowledge-integration/inline.md +7 -0
  28. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/task-source/contract.md +9 -0
  29. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/task-source/local.md +8 -0
  30. prompt_linker-0.8.0/Examples/TestConfiguration/contracts/task-source/tracker.md +9 -0
  31. prompt_linker-0.8.0/Examples/TestConfiguration/skeletons/autonomous-agent/agent.md +47 -0
  32. prompt_linker-0.8.0/Examples/TestConfiguration/skeletons/autonomous-agent/glossary.md +10 -0
  33. prompt_linker-0.8.0/LICENSE +21 -0
  34. prompt_linker-0.8.0/PKG-INFO +113 -0
  35. prompt_linker-0.8.0/README.md +93 -0
  36. prompt_linker-0.8.0/Roadmap/Roadmap.md +114 -0
  37. prompt_linker-0.8.0/pyproject.toml +69 -0
  38. prompt_linker-0.8.0/src/prompt_linker/__init__.py +6 -0
  39. prompt_linker-0.8.0/src/prompt_linker/check.py +417 -0
  40. prompt_linker-0.8.0/src/prompt_linker/cli.py +156 -0
  41. prompt_linker-0.8.0/src/prompt_linker/compiler.py +691 -0
  42. prompt_linker-0.8.0/tests/__init__.py +0 -0
  43. prompt_linker-0.8.0/tests/conftest.py +112 -0
  44. prompt_linker-0.8.0/tests/test_check.py +220 -0
  45. prompt_linker-0.8.0/tests/test_cli.py +71 -0
  46. prompt_linker-0.8.0/tests/test_compile.py +122 -0
  47. prompt_linker-0.8.0/tests/test_examples.py +26 -0
  48. prompt_linker-0.8.0/tests/test_frontmatter.py +37 -0
  49. prompt_linker-0.8.0/tests/test_resolution.py +118 -0
  50. prompt_linker-0.8.0/tests/test_security_scan.py +103 -0
  51. prompt_linker-0.8.0/tests/test_symbol_table.py +100 -0
  52. prompt_linker-0.8.0/tests/test_verify.py +107 -0
@@ -0,0 +1,40 @@
1
+ # --- prompt-linker generated artifacts ---
2
+ # Compiled instruction sets are DERIVED STATE: regenerate, never hand-edit.
3
+ # (See Docs/PromptLinker.md §6 — the compiled artifact must never be committed.)
4
+ compiled/
5
+ compiled-annotated/
6
+ *.compiled.md
7
+ .prompt-linker-cache/
8
+
9
+ # --- Python ---
10
+ __pycache__/
11
+ *.py[cod]
12
+ *.egg-info/
13
+ .eggs/
14
+ build/
15
+ dist/
16
+ .venv/
17
+ venv/
18
+ env/
19
+ .pytest_cache/
20
+ .mypy_cache/
21
+ .ruff_cache/
22
+ .coverage
23
+ htmlcov/
24
+
25
+ # --- Node ---
26
+ node_modules/
27
+ npm-debug.log*
28
+ yarn-error.log*
29
+ pnpm-debug.log*
30
+ *.tgz
31
+
32
+ # --- Claude Code (personal/local only; shared .claude/settings.json is committed) ---
33
+ .claude/settings.local.json
34
+
35
+ # --- Editors / OS ---
36
+ .vscode/
37
+ .idea/
38
+ *.swp
39
+ .DS_Store
40
+ Thumbs.db
@@ -0,0 +1,94 @@
1
+ # Changelog
2
+
3
+ All notable changes to **prompt-linker** are recorded here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ Group entries under `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, or `Security`.
9
+ Keep an `[Unreleased]` section at the top; on release, rename it to the new version + date and
10
+ start a fresh `[Unreleased]`.
11
+
12
+ ## [Unreleased]
13
+
14
+ ### Changed
15
+ - The published source archive (sdist) now ships only consumer-relevant files.
16
+ `[tool.hatch.build.targets.sdist]` excludes git-tracked maintainer-only directories
17
+ (`Roadmap/private/`, `Docs/private/`) and repo scaffolding not meant to travel with the tool or enter
18
+ a consuming repo's agent context (`CLAUDE.md`, `.claude/`, `.github/`). The public `Docs/` describe
19
+ the security scan at the level of which classes of injection are caught and the hard-fail vs advisory
20
+ contract; lower-level internal notes live in the repo only. The wheel was already limited to the
21
+ package modules.
22
+
23
+ ### Added
24
+ - **Content-addressed default output.** With no `--out`, `compile` writes to
25
+ `compiled/<name>-<config-hash>/` and prints that path, so distinct builds never collide and a host
26
+ can freeze a run by recording it (§7.3, resolves PC-OQ-4). The new **`config-hash`** fingerprints the
27
+ bindings **plus** the text of every source and inlined impl (stamped in the header next to
28
+ `resolution-hash`), so editing an impl body yields a fresh dir — a frozen build is never silently
29
+ overwritten.
30
+ - **`compile --force`** and a fail-closed overwrite guard: writing over a non-empty directory that
31
+ prompt-linker did not generate (no build marker) is refused unless `--force`; overwriting a previous
32
+ build is always allowed (derived state).
33
+ - **`check --deep`**: a configuration-level (cross-file) coherence pass on top of the per-file one.
34
+ All compiled files are reviewed together, so partner blocks inlined into *different* files (a writer
35
+ in one, a reader in another) are still cross-checked — closing the per-file pass's structural blind
36
+ spot (Verification §2.1).
37
+ - The annotated build now embeds each block's **contract signature** in its block marker, giving the
38
+ coherence check the contract as context. It is framed as *context, not ground truth* — a block may
39
+ not fit its placement, so the reviewer judges the assembled text on its own merits (Verification
40
+ §2.1, PromptLinker §7.4).
41
+
42
+ ### Changed
43
+ - Resolved the slot-granularity open question (was PC-OQ-1): contract size is the configuration
44
+ author's call, not the tool's. Documented the actual requirement instead — a `contract.md` must
45
+ state Input / Output / Invariant concretely enough that substitutability is checkable (PromptLinker
46
+ §4.2); moved the item from Roadmap "Open questions" to "Done".
47
+ - Resolved the impl-composition open question (was PC-OQ-2): a slot binds **exactly one** impl;
48
+ ordered multi-impl binding stays unsupported. Sequencing or layering a cross-cutting concern is done
49
+ by **slot composition** — multiple slots, each its own contract (PromptLinker §4.1); moved from
50
+ Roadmap "Open questions" to "Done".
51
+ - Resolved the cross-contract-dependencies open question (was PC-OQ-3): decided **against** a formal
52
+ `provides`/`requires` capability system. Partner-contract coupling is covered by the AI coherence
53
+ check instead, strengthened by the embedded-contract context and `check --deep` (above); moved from
54
+ Roadmap "Open questions" to "Done" and retired the related "partnership enforcement" backlog item.
55
+ - Resolved the artifact-location open question (was PC-OQ-4) as a boundary: the linker emits a
56
+ content-addressed artifact and prints its path (above); the host records that path and points its
57
+ agent at it. `compile`'s default `--out` is no longer the fixed `compiled/` directory. Moved from
58
+ Roadmap "Open questions" to "Done"; trimmed the "per-run freeze record" backlog item to its
59
+ remaining host-side half.
60
+ - Resolved the partial-recompilation open question (was PC-OQ-5): **full recompile**, always —
61
+ per-contract dependency tracking is rejected (it reintroduces cached staleness, §4.3, for a
62
+ non-existent cost). Output-level dedup is already provided by the content-addressed dir (PC-OQ-4).
63
+ Doc-only; moved from Roadmap "Open questions" to "Done".
64
+ - Resolved the per-slot-binding open question (was PC-OQ-6): binding stays **per-contract by
65
+ principle** — a slot names a contract *type*, never an implementation (Liskov substitutability, §2),
66
+ so per-slot / named-slot binding is declined, not deferred. With this, **all PC-OQ-1..6 are
67
+ resolved** and Roadmap "Open questions" is empty. Doc-only.
68
+
69
+ ## [0.8.0] — 2026-06-25
70
+
71
+ First documented release. Establishes the working linker, the verification layers, and the CLI.
72
+
73
+ ### Added
74
+ - **Deterministic linker** (`compiler.py`): a symbol table built fresh each run from front-matter
75
+ identity (`contract:` / `impl:`), layered resolution `defaults → preset → overrides`, slot
76
+ inlining, static-file mirroring, and a provenance `GENERATED` header (resolved bindings +
77
+ resolution hash + origin).
78
+ - **Structural verifier**: fail-closed coverage / identity / fit checks, the §8 override-layer rule
79
+ (overrides may touch only run-local contracts), preset `extends` with cycle detection, and
80
+ location-vs-identity advisories.
81
+ - **Deterministic security scan** (Verification §3.2): invisible/bidi control-character hard-fail,
82
+ capability-envelope screens (`network` / `tools` / `secrets`), and additional injection heuristics.
83
+ - **AI verifier** (`check.py`): opt-in conformance / coherence / security passes via Claude with
84
+ structured (JSON-schema) output; all model-boundary failures funnelled into `LinkError`. `--library`
85
+ and `--security` modes.
86
+ - **CLI** (`cli.py`): `compile`, `verify`, `check`, with shared `--preset` / `--set` overrides and
87
+ `--annotated` debug builds.
88
+ - **Examples**: runnable `StarterTemplate` and `TestConfiguration` configurations.
89
+ - **Docs**: `PromptLinker.md` (design), `Verification.md`, `Commands.md`, `Errors.md`.
90
+ - **Quality gates**: `pytest` suite (77 tests), `ruff` (line length 100), `mypy --strict`, wired into
91
+ GitHub Actions CI (Python 3.11 / 3.12).
92
+
93
+ [Unreleased]: https://github.com/ega-ega/prompt-linker/compare/v0.8.0...HEAD
94
+ [0.8.0]: https://github.com/ega-ega/prompt-linker/releases/tag/v0.8.0
@@ -0,0 +1,105 @@
1
+ # Prompt Linker — CLI commands
2
+
3
+ Every command takes the form:
4
+
5
+ ```
6
+ prompt-linker <command> [ROOT] [options]
7
+ ```
8
+
9
+ `ROOT` is a **configuration** directory — it holds `Linker.yaml`, `skeletons/`, and `contracts/`
10
+ (see [`PromptLinker.md`](./PromptLinker.md)). It defaults to the current directory. Installed via
11
+ `pipx`/`uvx` the entry point is `prompt-linker`; from a source checkout use
12
+ `PYTHONPATH=src python -m prompt_linker.cli`.
13
+
14
+ There are three commands: **`verify`** and **`compile`** are deterministic and use no model tokens;
15
+ **`check`** is the opt-in, model-using AI verifier.
16
+
17
+ ## Shared options
18
+
19
+ These apply to all three commands and select the resolution (`defaults → preset → overrides`, §3a):
20
+
21
+ | Option | Meaning |
22
+ |---|---|
23
+ | `--preset NAME` | Resolve from a named preset in the manifest (overrides the manifest's own `preset:`). |
24
+ | `--set CONTRACT=IMPL` | Per-contract override; repeatable. Run-local contracts only — overriding a shared-state-coupled contract is an error (§8). |
25
+
26
+ ---
27
+
28
+ ## `verify`
29
+
30
+ ```
31
+ prompt-linker verify [ROOT] [--preset NAME] [--set CONTRACT=IMPL ...]
32
+ ```
33
+
34
+ Proves the configuration is coherent and **writes nothing**. It runs exactly the checks `compile`
35
+ runs — coverage, symbol-table integrity, contract fit, the §8 split — plus the deterministic
36
+ **security scan** (injection screens: invisible/bidi characters and capability-envelope violations;
37
+ [`Verification.md`](./Verification.md) §3.2).
38
+
39
+ **Fail closed:** any violation prints `prompt-linker: <message>` to stderr and exits **1**; non-fatal
40
+ advisories print `prompt-linker: warning: <message>` and exit **0**. Every message is catalogued in
41
+ [`Errors.md`](./Errors.md).
42
+
43
+ ---
44
+
45
+ ## `compile`
46
+
47
+ ```
48
+ prompt-linker compile [ROOT] [--preset NAME] [--set CONTRACT=IMPL ...] [--out DIR] [--annotated] [--force]
49
+ ```
50
+
51
+ Resolves the manifest, verifies (same checks as `verify`), inlines the chosen implementations into the
52
+ skeletons, and writes the result. Compiled output is **derived state** — gitignored, regenerated,
53
+ never hand-edited (§6). The whole `skeletons/` tree is compiled and mirrored into the output dir, and
54
+ a final line reports the output dir and its `config-hash`.
55
+
56
+ | Option | Meaning |
57
+ |---|---|
58
+ | `--out DIR` | Output directory under ROOT. **Omitted → content-addressed:** `compiled/<name>-<config-hash>/`, so distinct builds never collide and a host can freeze a run by recording that path (§7.3, Roadmap PC-OQ-4). An explicit `--out` writes there verbatim — the caller then manages freeze. |
59
+ | `--annotated` | Emit a **debug build** with per-block `<!-- block: … -->` markers, for the AI verifier — **never a runtime artifact** (its header is stamped `ANNOTATED BUILD — NOT for a runtime agent`). Point it at a separate `--out`. |
60
+ | `--force` | Overwrite a non-empty `--out` that prompt-linker did **not** generate. By default the compiler **fails closed** rather than clobber a directory without its build marker (e.g. a mistaken `--out src`); overwriting a *previous* prompt-linker build is always allowed (derived state, §6). |
61
+
62
+ The **`config-hash`** identifies the *artifact* (resolved bindings **plus** the text of every source
63
+ and inlined impl), so editing an impl's body yields a fresh hash and a fresh output dir — a previously
64
+ frozen build is never silently overwritten. It is distinct from the header's `resolution-hash`, which
65
+ fingerprints the *bindings* only.
66
+
67
+ The release artifact (plain `compile`) is flat and clean — no per-block markers, no authoring
68
+ scaffolding (§6).
69
+
70
+ ---
71
+
72
+ ## `check`
73
+
74
+ ```
75
+ prompt-linker check [ROOT] [--preset NAME] [--set CONTRACT=IMPL ...] [--library] [--security] [--deep]
76
+ ```
77
+
78
+ The **AI verifier** — behavioral checks a deterministic pass cannot make ([`Verification.md`](./Verification.md)
79
+ §2, §3.3). Opt-in and model-using: install the extra (`pip install "prompt-linker[ai]"`) and set
80
+ `ANTHROPIC_API_KEY`; model `claude-opus-4-8`. It is **read-only** — it judges and reports, and never
81
+ edits artifacts. Output goes to stdout; exit is **1** if there are any findings, **0** otherwise.
82
+
83
+ Default (no flags) runs two passes:
84
+
85
+ - **conformance** — does each *selected* implementation actually satisfy its contract? One judgment
86
+ per unique `(contract, impl)` pair (deduped).
87
+ - **coherence** — do the inlined blocks of each compiled file fit together (and not assume something
88
+ an earlier phase never produced)? Each block carries its **contract signature** as context for this
89
+ judgment — context, not ground truth: a block may sit in a placement its contract does not fit, so
90
+ the verifier judges the text on its own merits.
91
+
92
+ | Option | Meaning |
93
+ |---|---|
94
+ | `--library` | Run conformance over **every** implementation of every contract (a source-level audit), not just the selected ones. Skips coherence (nothing is assembled). |
95
+ | `--security` | Also run the AI **injection review** — per implementation (anchored to its capability envelope) and over each whole compiled artifact (catches injection split across blocks). |
96
+ | `--deep` | Add a **configuration-level (cross-file) coherence** pass on top of the per-file one — all compiled files are reviewed together, so partner blocks that land in *different* files are still cross-checked (a writer in one file, a reader in another). Catches the cross-contract mismatch the per-file pass structurally cannot see ([`Verification.md`](./Verification.md) §2.1; Roadmap PC-OQ-3). No effect with `--library`, or when only one file has slots. |
97
+
98
+ ---
99
+
100
+ ## Exit codes
101
+
102
+ | Code | Meaning |
103
+ |---|---|
104
+ | `0` | Success. Advisories may have been printed as warnings. |
105
+ | `1` | A deterministic violation (`verify`/`compile`), or the AI verifier reported at least one finding (`check`), or a usage/parse error. |
@@ -0,0 +1,112 @@
1
+ # Prompt Linker — Compilation errors & advisories
2
+
3
+ Every check the linker performs, the exact message it emits, why it fires, and how to fix it. The
4
+ design rationale for each rule is in [`PromptLinker.md`](./PromptLinker.md) (section refs below).
5
+
6
+ ## How errors surface
7
+
8
+ - **Errors fail closed.** Any violation raises a typed `LinkError`; the linker writes **nothing** and
9
+ exits non-zero (§7.1). `verify` and `compile` run the *same* checks — `verify` just writes nothing.
10
+ CLI output: `prompt-linker: <message>` on stderr, exit code **1**.
11
+ - **Advisories never block.** Non-fatal issues print `prompt-linker: warning: <message>` on stderr and
12
+ compilation still succeeds (exit **0**).
13
+ - Messages below show interpolated parts as `<…>`; the literal text is what you can search for.
14
+
15
+ Checks run in this order (so the *first* failure is the one you see): parse/load → index (symbol
16
+ table) → resolve → gather sources → verify.
17
+
18
+ ---
19
+
20
+ ## Parse / load
21
+
22
+ | Message | When | Fix |
23
+ |---|---|---|
24
+ | `no manifest at <path>` | No `Linker.yaml` at the ROOT directory. | Run against a configuration directory, or add `Linker.yaml`. |
25
+ | `<path>: top level must be a mapping` | `Linker.yaml` is not a YAML mapping (e.g. a list or scalar). | Make the top level `key: value` pairs. |
26
+ | `<path>: presets must be a mapping` | `presets:` is present but not a mapping of name → bindings. | Use `presets:\n name:\n contract: impl`. |
27
+ | `<path>: overrides: expected a mapping` | `overrides:` (or a preset body) is not a mapping. | Use `contract: impl` pairs. |
28
+ | `<path>: preset '<name>': expected a mapping` | A preset body is not a mapping. | Same — `contract: impl` pairs under the preset. |
29
+ | `front-matter must be a mapping` | A file's `--- … ---` front-matter parses to a non-mapping. | Put `key: value` pairs between the `---` fences. |
30
+ | `bad --set '<item>'; expected CONTRACT=IMPL` | A CLI `--set` argument is malformed (missing `=`, empty side). | Pass `--set contract=impl`. |
31
+
32
+ ---
33
+
34
+ ## Index — building the symbol table (§4.3, §7.1)
35
+
36
+ The linker scans `contracts/**/*.md`, reads each file's front-matter identity, and builds
37
+ `(contract, impl) → path`. Identity is the front-matter, not the path.
38
+
39
+ | Message | When | Fix |
40
+ |---|---|---|
41
+ | `no implementation library at <base>` | The configuration has no `contracts/` directory. | Create `contracts/` with at least the contracts your skeletons reference. |
42
+ | `<path>: missing contract: in front-matter` | A file under `contracts/` has no `contract:` key. | Add `contract: <id>` front-matter (and `impl:` if it is an implementation). |
43
+ | `multiple definition of (<contract>, <impl>): <a> and <b> (§7.1)` | Two files declare the same `(contract, impl)` — a duplicate symbol. | Remove or re-identify one. Location does not disambiguate; the identity does. |
44
+ | `contract '<contract>' defined twice: <a> and <b>` | Two `contract.md`-style files declare the same contract id. | Keep one canonical `contract.md` per contract. |
45
+ | `<path>: class '<cls>' must be 'run-local' or 'shared-state-coupled' (§8)` | A contract's `class:` is an unknown value. | Use exactly `run-local` or `shared-state-coupled`. |
46
+
47
+ ---
48
+
49
+ ## Resolve — manifest → binding set (§3a)
50
+
51
+ | Message | When | Fix |
52
+ |---|---|---|
53
+ | `unknown preset '<name>'; known presets: <known>` | `--preset`/manifest `preset:` names a preset not in `presets:`. | Use one of the listed names, or define it. |
54
+ | `preset inheritance cycle through '<name>'` | A preset's `extends:` chain loops back on itself. | Break the cycle in the `extends:` chain. |
55
+
56
+ ---
57
+
58
+ ## Gather sources (§4.5)
59
+
60
+ | Message | When | Fix |
61
+ |---|---|---|
62
+ | `no skeletons directory at <base>` | The configuration has no `skeletons/` directory. | Add `skeletons/` with at least one skeleton or static file. |
63
+ | `no skeleton or static files under <base>` | `skeletons/` exists but is empty. | Put a skeleton (a file with `{{ slot: … }}`) or a static file under it. |
64
+
65
+ ---
66
+
67
+ ## Verify — coherence of the resolution (§7.1, §8)
68
+
69
+ Run for every contract referenced by a slot in any skeleton.
70
+
71
+ | Message | When | Fix |
72
+ |---|---|---|
73
+ | `contract '<contract>' is referenced by a skeleton but unbound` | A slot references a contract with no binding (no default, no preset value, no override). | Give the contract a `default:`, set it in the preset, or pass `--set`. |
74
+ | `contract '<contract>' is bound but has no contracts/<contract>/contract.md` | A binding names a contract that has no `contract.md` signature. | Add `contracts/<contract>/contract.md` (front-matter `contract:` + `class:`). |
75
+ | `contract '<contract>' bound to impl '<impl>', but no such implementation exists in the symbol table (§7.1)` | The chosen impl is not defined for that contract. | Fix the impl name in the preset/override, or add the impl file with matching front-matter. |
76
+ | `contract '<contract>' is shared-state-coupled; it cannot be set in the override layer — shared-state-coupled bindings are environment-global (§8)` | An `overrides:`/`--set` entry targets a `shared-state-coupled` contract. | Set it in the preset (the environment-global layer), not as a per-run override. Only run-local contracts are overridable. |
77
+
78
+ ---
79
+
80
+ ## Advisories (non-fatal)
81
+
82
+ These print as `warning:` and do **not** block compilation.
83
+
84
+ | Message | When | Note |
85
+ |---|---|---|
86
+ | `orphan contract '<contract>': defined but referenced by no skeleton` | A contract exists in the library but no skeleton has a slot for it. | Harmless; remove the contract if it is dead, or add the slot if it was forgotten. |
87
+ | `impl (<contract>, <impl>) lives at <rel>, not the conventional contracts/<contract>/<impl>.md` | A file's location disagrees with its declared identity. | Resolution still works (identity is the front-matter, §4.3); move the file to keep the tree tidy. |
88
+
89
+ ---
90
+
91
+ ## Security scan — deterministic (in `verify`; Verification §3.2)
92
+
93
+ Runs over selected impl bodies (envelope-aware) plus skeleton/static text. Two outcomes:
94
+
95
+ - **Hard-fail (fail-closed)** — raised together as one error, `prompt-linker: security scan: <N> hard
96
+ finding(s) — injection risk (Verification §3.2):` with one line per finding (each names the detector,
97
+ the `<file>:<line>`, and what to fix). Exit **1**, nothing is written. Caught classes: invisible/bidi
98
+ control characters, and impls that break their contract's declared `allow` envelope (§3.1).
99
+ - **Advisory** — `prompt-linker: warning: security [<kind>] <file>:<line>: <detail>`; never blocks
100
+ (exit **0**). Review each; declaring an `allow` envelope promotes a real policy to a hard-fail.
101
+
102
+ The **exact** per-finding catalog is kept in the repo only, not in the published package. Maintainers:
103
+ see `Docs/private/Errors.md` and the `compiler.py` comments.
104
+
105
+ ## Security & behavioral — AI verifier (`check`; Verification §2, §3.3)
106
+
107
+ `prompt-linker check` is model-using and opt-in. Its findings are reported to stdout (non-zero exit on
108
+ any), not raised as `LinkError`. The one hard error it can raise:
109
+
110
+ | Message | When | Fix |
111
+ |---|---|---|
112
+ | `the AI verifier needs the 'anthropic' package — install it with pip install "prompt-linker[ai]" …` | `check` invoked without the optional `anthropic` dependency. | `pip install "prompt-linker[ai]"`, and set `ANTHROPIC_API_KEY`. |