You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(rfc): record the two RFC-compliance gaps this review exposed
Two mechanisms, both found by independent review rather than by a gate.
A false RFC claim propagated unchecked because 55 of 162 enrolled RFCs
have
no full text under rfc/full/ -- including rfc7854 and rfc9069, the two
this
work was done under. rfc_requirements.py already knows it cannot judge
them
("no source text under `rfc/full/` -- cannot judge"), and ze-rfc.md step
2
says to read a file that for a third of enrolled RFCs has never existed.
So
ze-rfc-check validates those summaries against themselves. That permits
a
requirement the RFC does not contain, and -- the dangerous one, because
the
ledger looks complete -- a requirement it does contain that was never
extracted.
Three tagged-test authorisations remain outstanding and are recorded
rather
than worked around: the BMP ReplayID stamp
(TestStartLocRIBTriggersInitialDump
asserts replay.Broadcast specifically, which is over-specified against
the
obligation), the BMP mixed-family End-of-RIB, and the reactor AIGP case
inside orderCases(). The hook blocked each and no agent self-authorised.
Copy file name to clipboardExpand all lines: ai/INDEX.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -193,6 +193,7 @@ artifact type. Check them whenever your work touches the described concern.
193
193
|`learned_numbers.py`|`scripts/dev/`| Keep `plan/learned/NNN-*.md` numbering sound: no two summaries share a number, and each H1 number matches its filename. `learned-next` allocates max(existing prefixes)+1 against the local tree only, so parallel branches collide and only a merge or rebase reveals it. `--check` (gate: `make ze-learned-numbers-check`, folded into `make ze-doc-test` and `ze-regen-check`); `--fix` (`make ze-learned-numbers-fix`) keeps the most-referenced summary at the contested number, renumbers the rest above the highest, and rewrites references. Run after any merge/rebase touching `plan/learned/`. |
194
194
|`digest_check.py`|`scripts/dev/`| Validate the `file:line` anchors in `ai/digests/*.md`: each resolves to a real file (subsystem-relative via the digest's `<!-- digest-base: -->` header) and an in-range line. Keeps the hand-maintained flow digests honest as code moves. Gate: `make ze-digest-check`, folded into `make ze-doc-test`. |
195
195
|`spec-closure-check.py`|`scripts/dev/`| Detect specs implemented but never closed. `--list` shows the backlog in two tiers (high-confidence vs NEEDS VERIFICATION); `--spec <s>` exits 3 only for high-confidence (committed `plan/learned/NNN-<slug>.md` whose slug exactly equals the spec stem, spec `in-progress`, not an umbrella). Backs the Stop-hook closure gate. See `ai/rules/planning.md` "Closure Enforcement". |
196
+
|`ci_observer_recover_check.py`|`scripts/dev/`| Guard the `.ci` observer fail-closed property: no engine-touching call may sit inside a **recovering**`except` handler, because an exception unwinding through the observer's `finally` shutdown lands its sentinel on a stderr nothing relays -- the ordering defect that let real RPC errors pass as green in 332 of 346 observer files. The flagged call set is DERIVED (transitive closure over `ze_api.py` to `_call_engine`/`wait_for_shutdown`), so a new engine-touching helper is covered the day it is written. Its Go test runs the real scan and asserts zero, so `make ze-unit-test` enforces it with no make target to forget. See `ai/rules/testing.md` "Observer-Exit Antipattern". |
196
197
|`go_extract.go`|`scripts/dev/`| Move Go symbols between files |
197
198
|`replace.py`|`scripts/dev/`| Bulk find-and-replace with diff preview (run without `--apply` to review, then `--apply` to write). Supports `--regex` and `--all`. |
198
199
|`yang_move.py`|`scripts/dev/`| Format-aware YANG path refactoring. When YANG nodes move, updates slash paths, set commands, brace blocks, and GetContainer chains across the codebase. `remove <seg> --under <path>`, `rename <old> <new> --under <path>`, `move <src> <dst>`. Preview by default, `--apply` to write. Run `--test` for self-tests. |
| `RFC9234-4.1-2` | MUST NOT | 4.1 | `internal/component/bgp/plugins/role/config_test.go:290` | -- | {single-polarity} parseRoleContainer (internal/component/bgp/plugins/role/config.go:66) reads a single import role per peer and extractRoleCapabilities (config.go:213) emits exactly one CapabilityDecl per peer, so no code path can advertise multiple Role capabilities and only the exactly-one assertion is constructible |
@@ -4729,18 +4729,18 @@ An RFC is **enrolled** (`rfc/enrolled.txt`) when every MUST-level requirement it
| `RFC9234-5-10` | MUST NOT | 5 | `internal/component/bgp/plugins/role/otc_test.go:1357` | `internal/component/bgp/plugins/role/otc_test.go:967` | |
4733
-
| `RFC9234-5-11` | MUST NOT | 5 | `internal/component/bgp/plugins/role/otc_test.go:1652` | -- | {single-polarity} checkOTCIngress (internal/component/bgp/plugins/role/otc.go:164) and OTCEgressFilter (otc.go:384) take no operator override, peerRoleConfig (config.go:17) exposes no disable flag, and the wire-bytes OTC suppression at otc.go:384 runs before and independent of the export policy, so the procedures cannot be switched off by configuration and a modifiable negative is not constructible |
| `RFC9234-5-10` | MUST NOT | 5 | `internal/component/bgp/plugins/role/otc_test.go:1368`, `internal/component/bgp/plugins/role/otc_test.go:1960`, `internal/component/bgp/plugins/role/otc_test.go:2003`, `internal/component/bgp/plugins/role/otc_test.go:2043` | `internal/component/bgp/plugins/role/otc_test.go:969` | |
4733
+
| `RFC9234-5-11` | MUST NOT | 5 | `internal/component/bgp/plugins/role/otc_test.go:1665` | -- | {single-polarity} checkOTCIngress (internal/component/bgp/plugins/role/otc.go:164) and OTCEgressFilter (otc.go:384) take no operator override, peerRoleConfig (config.go:17) exposes no disable flag, and the wire-bytes OTC suppression at otc.go:384 runs before and independent of the export policy, so the procedures cannot be switched off by configuration and a modifiable negative is not constructible |
| `RFC9234-5-7` | MUST | 5 | -- | -- | {not-applicable} ze does not operate as an AS Confederation (no confederation-identifier or member-AS config exists anywhere in config or the role plugin); the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses only dest.LocalAS, so there is no confederation egress boundary at which a confederation identifier could be stamped |
4742
4742
| `RFC9234-5-8` | MUST NOT | 5 | -- | -- | {not-applicable} ze has no AS Confederation membership (no member-AS or confederation-identifier config); the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses only dest.LocalAS, so an UPDATE never carries a member-AS OTC value at a confederation boundary |
4743
-
| `RFC9234-5-9` | MUST NOT | 5 | `internal/component/bgp/plugins/role/otc_test.go:1324` | -- | {single-polarity} the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses dest.LocalAS, the effective per-peer internet-facing local AS supplied by the reactor at internal/component/bgp/reactor/peer_forward_facts.go:133, and no code path stamps any other value, so a wrong-ASN negative is not constructible |
4743
+
| `RFC9234-5-9` | MUST NOT | 5 | `internal/component/bgp/plugins/role/otc_test.go:1335` | -- | {single-polarity} the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses dest.LocalAS, the effective per-peer internet-facing local AS supplied by the reactor at internal/component/bgp/reactor/peer_forward_facts.go:133, and no code path stamps any other value, so a wrong-ASN negative is not constructible |
4744
4744
| `RFC9234-6-1` | MUST NOT | 6 | -- | -- | {not-applicable} ze has no representation of a Complex peering relationship; parseRoleContainer (internal/component/bgp/plugins/role/config.go:66) parses one role per peer with no relationship-complexity classification, so there is no ze code path that could place a role on a complex session to guard against |
Copy file name to clipboardExpand all lines: ai/rules/testing.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -342,7 +342,7 @@ the two wired conventions, never a bare test file plus hope:
342
342
343
343
| Your tool | Convention | Runs because |
344
344
|-----------|-----------|--------------|
345
-
| Has its own unit tests | Name them `scripts/dev/<tool>_test.py` (unittest, with `unittest.main()`) |`TestPythonUnitTests` (`scripts/dev/python_tests_test.go`) globs `*_test.py` and runs each. A new file is picked up automatically |
345
+
| Has its own unit tests | Name them `<tool>_test.py` (unittest, with `unittest.main()`) and put them BESIDE the tool -- `scripts/dev/` or `test/scripts/`|`TestPythonUnitTests` (`scripts/dev/python_tests_test.go`) globs `*_test.py`under BOTH roots and runs each. A new file is picked up automatically, and each root carries its own non-empty assertion so a root that stops contributing fails loudly rather than silently covering nothing|
346
346
| Wants fixture tests inside the script | Add a `--selftest` flag, then a small Go test that shells out to it | The pattern of `dep_audit.py`, `migrate_module.py`, `qemu-run.py`. See `scripts/dev/migrate_module_test.go`|
347
347
348
348
Both land inside `go test`, so `make ze-unit-test` covers them via `go list ./...`
0 commit comments