Require explicit cadence profile assessment and correct contract pins
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e77d-47a4-7771-8e34-7339c7fac0e4
This commit is contained in:
parent
9383b94019
commit
36303d25a3
7 changed files with 281 additions and 20 deletions
|
|
@ -7,8 +7,8 @@ status: proposed
|
||||||
version: "0.1"
|
version: "0.1"
|
||||||
owner: net-kingdom
|
owner: net-kingdom
|
||||||
created: "2026-09-04"
|
created: "2026-09-04"
|
||||||
updated: "2026-09-05"
|
updated: "2026-09-28"
|
||||||
last_reviewed: "2026-09-05"
|
last_reviewed: "2026-09-28"
|
||||||
review_interval: 3m
|
review_interval: 3m
|
||||||
scope: evidence-completeness
|
scope: evidence-completeness
|
||||||
validator:
|
validator:
|
||||||
|
|
@ -34,14 +34,21 @@ This profile imports that contract and defines only NetKingdom security
|
||||||
obligations over conforming declarations.
|
obligations over conforming declarations.
|
||||||
|
|
||||||
The import is InfoTechCanon `standard/emission-cadence`, document version
|
The import is InfoTechCanon `standard/emission-cadence`, document version
|
||||||
`0.1.0`, schema version `0.1` (published in canon 0.7.0; upstream status: draft).
|
`0.2.0`, schema version `0.1` (canon 0.7.0; upstream status: candidate).
|
||||||
|
|
||||||
- Contract: `info-tech-canon/infospace/standards/emission-cadence/InfoTechCanonEmissionCadenceStandard.md`
|
- Contract: `info-tech-canon/infospace/standards/emission-cadence/InfoTechCanonEmissionCadenceStandard.md`
|
||||||
- Schema: `info-tech-canon/infospace/schemas/emission-cadence.schema.yaml`
|
- Schema: `info-tech-canon/infospace/schemas/emission-cadence.schema.yaml`
|
||||||
- Schema ID: `https://info-tech-canon.local/schemas/emission-cadence.schema.yaml`
|
- Schema ID: `https://info-tech-canon.local/schemas/emission-cadence.schema.yaml`
|
||||||
- Reviewed schema revision: `b081d39da1353201f879ee6832d4e3e52b791c73`
|
- Reviewed contract/schema revision: `4d0851c3fca306538b53838421f4499baf352778`
|
||||||
|
- Owner-published candidate bundle digest: `b08b4d95fc4b0bd3`
|
||||||
- Schema SHA-256: `6d52692eb1e4d1325e0d6062d95acded98beddaae5bcfe24c6f0e91f1b6be6ae`
|
- Schema SHA-256: `6d52692eb1e4d1325e0d6062d95acded98beddaae5bcfe24c6f0e91f1b6be6ae`
|
||||||
|
|
||||||
|
The candidate bundle digest identifies the exported contract, including its
|
||||||
|
standard text and example; it is not the schema SHA-256. The September 28
|
||||||
|
review confirmed that the wire schema is byte-identical to the earlier import.
|
||||||
|
InfoTechCanon corrected its adoption brief: `972c0b6701d1693f` identified the
|
||||||
|
0.1.0 draft bundle, not candidate 0.2.0.
|
||||||
|
|
||||||
The schema ID is an identifier; supply the file from the owner checkout, not a
|
The schema ID is an identifier; supply the file from the owner checkout, not a
|
||||||
network download from that hostname. This profile remains proposed pending
|
network download from that hostname. This profile remains proposed pending
|
||||||
owner-instance migration and validation. The King's Guard draft is provenance,
|
owner-instance migration and validation. The King's Guard draft is provenance,
|
||||||
|
|
@ -118,9 +125,26 @@ contract and refuses to profile a document that fails the imported schema.
|
||||||
from the source's authoritative event-class inventory; they are not guesses by
|
from the source's authoritative event-class inventory; they are not guesses by
|
||||||
the checker. Rare load-bearing assertions imply load-bearing.
|
the checker. Rare load-bearing assertions imply load-bearing.
|
||||||
|
|
||||||
MUST failures or generic contract failures produce a non-zero exit. Missing
|
The report separates `contract_valid` (JSON Schema validity) from
|
||||||
attributive declarations produce a SHOULD finding and succeed by default;
|
`profile_assessed` and nullable `conformant`. A profile assessment is performed
|
||||||
`--fail-on-should` is available for a stricter caller policy.
|
only after schema validation and with a nonempty supplied inventory. The report
|
||||||
|
records those assertions under `inventory` and marks `assessment_scope` as
|
||||||
|
`supplied-inventory`; its result covers only that inventory, not independently
|
||||||
|
verified completeness or operational emission.
|
||||||
|
|
||||||
|
Without inventory, default mode returns `profile_assessed: false`,
|
||||||
|
`conformant: null`, `assessment_scope: inventory-missing` and exit 2. Explicit
|
||||||
|
`--schema-only` returns `assessment_scope: schema-only` and exit 0 for a valid
|
||||||
|
schema instance, while leaving profile conformance unassessed. It cannot be
|
||||||
|
combined with inventory flags or `--fail-on-should`. Invalid schema/declaration
|
||||||
|
results return exit 1 with profile conformance unassessed. CLI/input errors
|
||||||
|
return exit 2.
|
||||||
|
|
||||||
|
MUST failures from an assessed profile produce exit 1. Missing attributive
|
||||||
|
declarations produce a SHOULD finding and succeed by default;
|
||||||
|
`--fail-on-should` is available for a stricter caller policy. Callers must check
|
||||||
|
`profile_assessed == true` and `conformant == true` before claiming profile
|
||||||
|
success; an empty findings list or schema-only success is insufficient.
|
||||||
|
|
||||||
## 5. Adoption gate
|
## 5. Adoption gate
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
# local-identity emission cadence — fit findings (INFO-WP-0029-T02)
|
# local-identity emission cadence — fit findings (INFO-WP-0029-T02)
|
||||||
|
|
||||||
Declaration: `local-identity/emission-cadence.yaml`, pinned to InfoTechCanon
|
Declaration: `local-identity/emission-cadence.yaml`, currently pinned to
|
||||||
emission contract digest `972c0b6701d1693f` (document 0.2.0, wire schema 0.1).
|
InfoTechCanon candidate bundle `b08b4d95fc4b0bd3` (document 0.2.0, wire schema
|
||||||
|
0.1). The September 21 evaluation used `972c0b6701d1693f`, then incorrectly
|
||||||
|
labelled 0.2.0 by the owner brief; that digest actually identifies the 0.1.0
|
||||||
|
draft. The owner corrected the brief on September 22. The schema bytes are
|
||||||
|
unchanged, and the historical findings below remain valid.
|
||||||
Emitter: `local-identity/src/local_identity/audit.py`.
|
Emitter: `local-identity/src/local_identity/audit.py`.
|
||||||
|
|
||||||
## Validation (2026-09-21)
|
## Validation (2026-09-21)
|
||||||
|
|
@ -39,3 +43,13 @@ To close the gap, `serve` would have to emit a periodic `nothing-to-report`
|
||||||
heartbeat and a start/stop pair so that observers can bound the silence. That is
|
heartbeat and a start/stop pair so that observers can bound the silence. That is
|
||||||
a code change to a bootstrap-only tool and is not planned. This file records the
|
a code change to a bootstrap-only tool and is not planned. This file records the
|
||||||
incompatibility as the adoption result.
|
incompatibility as the adoption result.
|
||||||
|
|
||||||
|
## Pin correction and revalidation — 2026-09-28
|
||||||
|
|
||||||
|
The current declaration now uses the owner-published candidate bundle digest
|
||||||
|
`b08b4d95fc4b0bd3`. Schema SHA-256 remains
|
||||||
|
`6d52692eb1e4d1325e0d6062d95acded98beddaae5bcfe24c6f0e91f1b6be6ae`.
|
||||||
|
Revalidated against the owner schema with both documented classes explicitly
|
||||||
|
supplied as rare load-bearing: generic-valid, with exactly two
|
||||||
|
`rare-heartbeat-missing` findings. All 15 focused checker tests pass. No
|
||||||
|
heartbeat, observer feed or runtime emission change is implied by this pin fix.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Source-owned Emission Cadence declaration for local-identity (INFO-WP-0029-T02).
|
# Source-owned Emission Cadence declaration for local-identity (INFO-WP-0029-T02).
|
||||||
# Pinned to InfoTechCanon emission contract digest 972c0b6701d1693f
|
# Pinned to InfoTechCanon emission contract digest b08b4d95fc4b0bd3
|
||||||
# (document 0.2.0, wire schema 0.1).
|
# (document 0.2.0, wire schema 0.1).
|
||||||
#
|
#
|
||||||
# This states intended cadence only. It is not evidence that the events are
|
# This states intended cadence only. It is not evidence that the events are
|
||||||
|
|
@ -12,7 +12,7 @@ source: net-kingdom
|
||||||
stream_id: net-kingdom.local-identity.audit
|
stream_id: net-kingdom.local-identity.audit
|
||||||
extensions:
|
extensions:
|
||||||
netkingdom:
|
netkingdom:
|
||||||
contract_digest: 972c0b6701d1693f
|
contract_digest: b08b4d95fc4b0bd3
|
||||||
contract_document_version: 0.2.0
|
contract_document_version: 0.2.0
|
||||||
sources:
|
sources:
|
||||||
- source_id: net-kingdom.local-identity.audit.token-issued
|
- source_id: net-kingdom.local-identity.audit.token-issued
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,56 @@ classes passed with `--load-bearing`, `--rare-load-bearing`, and
|
||||||
`--attributive` come from the source's authoritative inventory; the checker
|
`--attributive` come from the source's authoritative inventory; the checker
|
||||||
does not infer them from names, payloads, or observed traffic.
|
does not infer them from names, payloads, or observed traffic.
|
||||||
|
|
||||||
|
## Assessment modes and results
|
||||||
|
|
||||||
|
A security-profile assessment requires at least one source-owned class
|
||||||
|
assertion. For example, to check local-identity's documented rare classes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 tools/emission-cadence-profile/emission_cadence_profile.py \
|
||||||
|
--contract-schema ../info-tech-canon/infospace/schemas/emission-cadence.schema.yaml \
|
||||||
|
--rare-load-bearing serve/token.token_issued \
|
||||||
|
--rare-load-bearing revoke-token \
|
||||||
|
local-identity/emission-cadence.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
This declaration currently fails both heartbeat obligations. To intentionally
|
||||||
|
check only its structure against the imported JSON Schema:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 tools/emission-cadence-profile/emission_cadence_profile.py \
|
||||||
|
--contract-schema ../info-tech-canon/infospace/schemas/emission-cadence.schema.yaml \
|
||||||
|
--schema-only local-identity/emission-cadence.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
| Invocation/result | `contract_valid` | `profile_assessed` | `conformant` | Exit |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Valid schema, no inventory, default mode | true | false | null | 2 |
|
||||||
|
| Valid schema, explicit `--schema-only` | true | false | null | 0 |
|
||||||
|
| Invalid schema/declaration, either mode | false | false | null | 1 |
|
||||||
|
| Supplied inventory, profile passes | true | true | true | 0 |
|
||||||
|
| Supplied inventory, profile fails | true | true | false | 1 |
|
||||||
|
|
||||||
|
`assessment_scope` is `schema-only`, `inventory-missing`, or
|
||||||
|
`supplied-inventory`. The report includes the exact sorted `inventory`
|
||||||
|
assertions. Profile results cover only those assertions: the checker cannot
|
||||||
|
prove that the caller supplied a complete inventory or that events are emitted
|
||||||
|
and observed. `contract_valid` means JSON Schema validity, not every semantic
|
||||||
|
rule in the generic standard; duplicate source IDs are checked during profile
|
||||||
|
assessment.
|
||||||
|
|
||||||
|
`--schema-only` cannot be combined with class assertions or `--fail-on-should`.
|
||||||
|
Blank class arguments are rejected. Invalid CLI options and unreadable input
|
||||||
|
also exit 2. SHOULD findings remain advisory unless `--fail-on-should` is used.
|
||||||
|
|
||||||
|
**Compatibility:** callers that previously omitted class arguments must now
|
||||||
|
choose schema-only validation or supply an inventory. `conformant` can be null;
|
||||||
|
automation claiming profile success must require `profile_assessed == true`
|
||||||
|
and `conformant == true`, rather than merely checking for no findings or an
|
||||||
|
exit code of zero. No evidence classification is inferred from the document.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
Run its tests with:
|
Run its tests with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -348,10 +348,17 @@ def build_report(
|
||||||
rare_load_bearing: set[str],
|
rare_load_bearing: set[str],
|
||||||
attributive: set[str],
|
attributive: set[str],
|
||||||
fail_on_should: bool = False,
|
fail_on_should: bool = False,
|
||||||
|
schema_only: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
|
inventory_supplied = bool(load_bearing or rare_load_bearing or attributive)
|
||||||
|
if schema_only and (inventory_supplied or fail_on_should):
|
||||||
|
raise ValueError("schema-only validation cannot include profile options")
|
||||||
|
if any(not name.strip() for name in load_bearing | rare_load_bearing | attributive):
|
||||||
|
raise ValueError("inventory event classes must not be blank")
|
||||||
findings = _schema_findings(contract_schema, declaration)
|
findings = _schema_findings(contract_schema, declaration)
|
||||||
contract_valid = not findings
|
contract_valid = not findings
|
||||||
if contract_valid:
|
profile_assessed = contract_valid and inventory_supplied and not schema_only
|
||||||
|
if profile_assessed:
|
||||||
findings.extend(
|
findings.extend(
|
||||||
evaluate_profile(
|
evaluate_profile(
|
||||||
declaration,
|
declaration,
|
||||||
|
|
@ -362,17 +369,37 @@ def build_report(
|
||||||
)
|
)
|
||||||
must_count = sum(item.level == "MUST" for item in findings)
|
must_count = sum(item.level == "MUST" for item in findings)
|
||||||
should_count = sum(item.level == "SHOULD" for item in findings)
|
should_count = sum(item.level == "SHOULD" for item in findings)
|
||||||
|
assessment_scope = "supplied-inventory" if inventory_supplied else "inventory-missing"
|
||||||
|
if schema_only:
|
||||||
|
assessment_scope = "schema-only"
|
||||||
return {
|
return {
|
||||||
"profile": PROFILE_ID,
|
"profile": PROFILE_ID,
|
||||||
"contract_schema": contract_schema_path,
|
"contract_schema": contract_schema_path,
|
||||||
"declaration": declaration_path,
|
"declaration": declaration_path,
|
||||||
"contract_valid": contract_valid,
|
"contract_valid": contract_valid,
|
||||||
"conformant": must_count == 0 and (not fail_on_should or should_count == 0),
|
"profile_assessed": profile_assessed,
|
||||||
|
"assessment_scope": assessment_scope,
|
||||||
|
"inventory": {
|
||||||
|
"load_bearing": sorted(load_bearing),
|
||||||
|
"rare_load_bearing": sorted(rare_load_bearing),
|
||||||
|
"attributive": sorted(attributive),
|
||||||
|
},
|
||||||
|
"conformant": (
|
||||||
|
must_count == 0 and (not fail_on_should or should_count == 0)
|
||||||
|
if profile_assessed
|
||||||
|
else None
|
||||||
|
),
|
||||||
"summary": {"must": must_count, "should": should_count},
|
"summary": {"must": must_count, "should": should_count},
|
||||||
"findings": [asdict(item) for item in findings],
|
"findings": [asdict(item) for item in findings],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _event_class(value: str) -> str:
|
||||||
|
if not value.strip():
|
||||||
|
raise argparse.ArgumentTypeError("event class must not be blank")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Validate an imported emission-cadence declaration against the NetKingdom profile."
|
description="Validate an imported emission-cadence declaration against the NetKingdom profile."
|
||||||
|
|
@ -380,16 +407,40 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||||
parser.add_argument("declaration", type=Path)
|
parser.add_argument("declaration", type=Path)
|
||||||
parser.add_argument("--contract-schema", required=True, type=Path)
|
parser.add_argument("--contract-schema", required=True, type=Path)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--load-bearing", action="append", default=[], metavar="EVENT_CLASS"
|
"--schema-only",
|
||||||
|
action="store_true",
|
||||||
|
help="Validate only the supplied JSON Schema; do not assess security-profile conformance.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--rare-load-bearing", action="append", default=[], metavar="EVENT_CLASS"
|
"--load-bearing",
|
||||||
|
action="append",
|
||||||
|
default=[],
|
||||||
|
type=_event_class,
|
||||||
|
metavar="EVENT_CLASS",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--attributive", action="append", default=[], metavar="EVENT_CLASS"
|
"--rare-load-bearing",
|
||||||
|
action="append",
|
||||||
|
default=[],
|
||||||
|
type=_event_class,
|
||||||
|
metavar="EVENT_CLASS",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--attributive",
|
||||||
|
action="append",
|
||||||
|
default=[],
|
||||||
|
type=_event_class,
|
||||||
|
metavar="EVENT_CLASS",
|
||||||
)
|
)
|
||||||
parser.add_argument("--fail-on-should", action="store_true")
|
parser.add_argument("--fail-on-should", action="store_true")
|
||||||
return parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
if args.schema_only and (
|
||||||
|
args.load_bearing or args.rare_load_bearing or args.attributive or args.fail_on_should
|
||||||
|
):
|
||||||
|
parser.error(
|
||||||
|
"--schema-only cannot be combined with profile inventory or --fail-on-should"
|
||||||
|
)
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
def main(argv: list[str] | None = None) -> int:
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
|
@ -409,8 +460,15 @@ def main(argv: list[str] | None = None) -> int:
|
||||||
rare_load_bearing=set(args.rare_load_bearing),
|
rare_load_bearing=set(args.rare_load_bearing),
|
||||||
attributive=set(args.attributive),
|
attributive=set(args.attributive),
|
||||||
fail_on_should=args.fail_on_should,
|
fail_on_should=args.fail_on_should,
|
||||||
|
schema_only=args.schema_only,
|
||||||
)
|
)
|
||||||
print(json.dumps(report, indent=2, sort_keys=True))
|
print(json.dumps(report, indent=2, sort_keys=True))
|
||||||
|
if not report["contract_valid"]:
|
||||||
|
return 1
|
||||||
|
if args.schema_only:
|
||||||
|
return 0
|
||||||
|
if not report["profile_assessed"]:
|
||||||
|
return 2
|
||||||
return 0 if report["conformant"] else 1
|
return 0 if report["conformant"] else 1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
import json
|
||||||
import pathlib
|
import pathlib
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
@ -92,14 +93,86 @@ def test_valid_rare_load_bearing_requires_both_positive_controls() -> None:
|
||||||
result = report(declaration(rare_entry()), rare={"audit.deny"})
|
result = report(declaration(rare_entry()), rare={"audit.deny"})
|
||||||
|
|
||||||
assert result["contract_valid"] is True
|
assert result["contract_valid"] is True
|
||||||
|
assert result["profile_assessed"] is True
|
||||||
|
assert result["inventory"]["rare_load_bearing"] == ["audit.deny"]
|
||||||
assert result["conformant"] is True
|
assert result["conformant"] is True
|
||||||
assert result["findings"] == []
|
assert result["findings"] == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_omitted_inventory_does_not_claim_profile_conformance() -> None:
|
||||||
|
item = rare_entry()
|
||||||
|
del item["heartbeat"]
|
||||||
|
result = report(declaration(item))
|
||||||
|
|
||||||
|
assert result["contract_valid"] is True
|
||||||
|
assert result["profile_assessed"] is False
|
||||||
|
assert result["conformant"] is None
|
||||||
|
assert result["assessment_scope"] == "inventory-missing"
|
||||||
|
assert result["findings"] == [] # Rarity is never inferred from the entry.
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"options,valid,exit_code,scope",
|
||||||
|
[
|
||||||
|
([], True, 2, "inventory-missing"),
|
||||||
|
(["--schema-only"], True, 0, "schema-only"),
|
||||||
|
(["--schema-only"], False, 1, "schema-only"),
|
||||||
|
([], False, 1, "inventory-missing"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_cli_unassessed_results(tmp_path, capsys, options, valid, exit_code, scope):
|
||||||
|
schema = tmp_path / "schema.yaml"
|
||||||
|
document = tmp_path / "declaration.yaml"
|
||||||
|
schema.write_text(yaml.safe_dump(CONTRACT_SCHEMA))
|
||||||
|
item = rare_entry()
|
||||||
|
del item["heartbeat"]
|
||||||
|
document.write_text(yaml.safe_dump(declaration(item) if valid else {}))
|
||||||
|
|
||||||
|
assert (
|
||||||
|
profile.main([str(document), "--contract-schema", str(schema), *options])
|
||||||
|
== exit_code
|
||||||
|
)
|
||||||
|
result = json.loads(capsys.readouterr().out)
|
||||||
|
assert result["contract_valid"] is valid
|
||||||
|
assert result["profile_assessed"] is False
|
||||||
|
assert result["conformant"] is None
|
||||||
|
assert result["assessment_scope"] == scope
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"options",
|
||||||
|
[
|
||||||
|
["--load-bearing", "audit.deny"],
|
||||||
|
["--rare-load-bearing", "audit.deny"],
|
||||||
|
["--attributive", "audit.allow"],
|
||||||
|
["--fail-on-should"],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_schema_only_refuses_profile_options(options):
|
||||||
|
with pytest.raises(SystemExit) as exc:
|
||||||
|
profile.parse_args(
|
||||||
|
["source.yaml", "--contract-schema", "schema.yaml", "--schema-only", *options]
|
||||||
|
)
|
||||||
|
assert exc.value.code == 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"option", ["--load-bearing", "--rare-load-bearing", "--attributive"]
|
||||||
|
)
|
||||||
|
def test_blank_class_is_not_an_inventory(option):
|
||||||
|
with pytest.raises(SystemExit) as exc:
|
||||||
|
profile.parse_args(
|
||||||
|
["source.yaml", "--contract-schema", "schema.yaml", option, " "]
|
||||||
|
)
|
||||||
|
assert exc.value.code == 2
|
||||||
|
|
||||||
|
|
||||||
def test_contract_validation_runs_before_profile() -> None:
|
def test_contract_validation_runs_before_profile() -> None:
|
||||||
result = report({"source": "example"}, rare={"audit.deny"})
|
result = report({"source": "example"}, rare={"audit.deny"})
|
||||||
|
|
||||||
assert result["contract_valid"] is False
|
assert result["contract_valid"] is False
|
||||||
|
assert result["profile_assessed"] is False
|
||||||
|
assert result["conformant"] is None
|
||||||
assert codes(result) == {"contract-validation-failed"}
|
assert codes(result) == {"contract-validation-failed"}
|
||||||
assert "load-bearing-cadence-missing" not in codes(result)
|
assert "load-bearing-cadence-missing" not in codes(result)
|
||||||
|
|
||||||
|
|
@ -254,8 +327,6 @@ def test_duplicate_source_ids_fail_even_with_distinct_event_classes(upstream_sch
|
||||||
def test_should_policy_and_cli(tmp_path, capsys):
|
def test_should_policy_and_cli(tmp_path, capsys):
|
||||||
schema = tmp_path / "schema.json"
|
schema = tmp_path / "schema.json"
|
||||||
document = tmp_path / "declaration.yaml"
|
document = tmp_path / "declaration.yaml"
|
||||||
import json
|
|
||||||
|
|
||||||
schema.write_text(json.dumps(CONTRACT_SCHEMA))
|
schema.write_text(json.dumps(CONTRACT_SCHEMA))
|
||||||
document.write_text(json.dumps(declaration()))
|
document.write_text(json.dumps(declaration()))
|
||||||
args = [
|
args = [
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ owner: codex
|
||||||
topic_slug: netkingdom
|
topic_slug: netkingdom
|
||||||
planning_priority: P1
|
planning_priority: P1
|
||||||
created: "2026-09-04"
|
created: "2026-09-04"
|
||||||
updated: "2026-09-07"
|
updated: "2026-09-28"
|
||||||
related:
|
related:
|
||||||
- GH-DEC-2026-004
|
- GH-DEC-2026-004
|
||||||
- canon/standards/security-layer-model_v0.7.md
|
- canon/standards/security-layer-model_v0.7.md
|
||||||
|
|
@ -122,6 +122,22 @@ checkout. Full reconciliation remains pending because API queries/writes timed
|
||||||
out or returned connection-refused errors. Generated index/intake metadata was
|
out or returned connection-refused errors. Generated index/intake metadata was
|
||||||
reviewed; the source files remain authoritative.
|
reviewed; the source files remain authoritative.
|
||||||
|
|
||||||
|
### Import metadata reconciled — 2026-09-28
|
||||||
|
|
||||||
|
Updated the importing profile to candidate document 0.2.0 / wire schema 0.1,
|
||||||
|
reviewed contract revision `4d0851c3fca306538b53838421f4499baf352778`, and
|
||||||
|
owner-published candidate bundle digest `b08b4d95fc4b0bd3`. Verified the schema
|
||||||
|
SHA-256 remains `6d52692eb1e4d1325e0d6062d95acded98beddaae5bcfe24c6f0e91f1b6be6ae`.
|
||||||
|
Corrected local-identity's current declaration pin and preserved the old pin
|
||||||
|
with its correction in the historical findings. No emission behavior changed.
|
||||||
|
|
||||||
|
All 15 focused cadence tests pass. Revalidation with the two source-owned
|
||||||
|
rare-class assertions is generic-valid and still returns exactly two
|
||||||
|
`rare-heartbeat-missing` findings. T04 remains `wait` for external source
|
||||||
|
migration, observer integration and the explicit local-identity incompatibility
|
||||||
|
resolution; the profile remains proposed. Metadata repair is complete and does
|
||||||
|
not count as source/observer adoption.
|
||||||
|
|
||||||
## Review the layer model's use of the profile
|
## Review the layer model's use of the profile
|
||||||
|
|
||||||
```task
|
```task
|
||||||
|
|
@ -153,3 +169,31 @@ profile, carries the volume/rare split explicitly, and states that
|
||||||
classification is the source's to publish and never the checker's to infer.
|
classification is the source's to publish and never the checker's to infer.
|
||||||
Change log item 6 and §14 record the review; the standard remains `proposed` and
|
Change log item 6 and §14 record the review; the standard remains `proposed` and
|
||||||
publication waits on the close of the circulation round.
|
publication waits on the close of the circulation round.
|
||||||
|
|
||||||
|
## Infrastructure review — 2026-09-28
|
||||||
|
|
||||||
|
T04 remains `wait`, but upstream publication is no longer the blocker.
|
||||||
|
The current generic document is candidate 0.2.0 with wire schema 0.1;
|
||||||
|
InfoTechCanon corrected the candidate bundle digest to `b08b4d95fc4b0bd3`
|
||||||
|
(the wire schema was unchanged). Review and update the profile's old
|
||||||
|
draft/document/revision description and local-identity's stale bundle pin
|
||||||
|
against the exact owner artifact before handoff; do not confuse a bundle digest
|
||||||
|
with the schema SHA-256.
|
||||||
|
|
||||||
|
Approval Engine and Qonto still carry draft-shaped owner envelopes. In addition,
|
||||||
|
NetKingdom now has its own source declaration at
|
||||||
|
`local-identity/emission-cadence.yaml`: generic validation passed, but both
|
||||||
|
rare load-bearing entries lack the required heartbeat. The source has no
|
||||||
|
audit-core sender/feed; its findings also record dropped audit I/O errors and
|
||||||
|
no completeness claim. Generic validity is not security-profile conformance
|
||||||
|
or an operating observer result.
|
||||||
|
|
||||||
|
Extend T04 acceptance to cover the local source explicitly: either implement
|
||||||
|
and evidence activity-scoped heartbeat/reconciliation with its owners, or
|
||||||
|
retain the documented incompatibility without claiming profile-wide adoption.
|
||||||
|
Resolve the declared heartbeat event class versus audit-core's registered
|
||||||
|
`heartbeat_classes` mapping, migrate the two external owner instances, and
|
||||||
|
obtain a real source/observer result before the King's Guard handoff. Keep
|
||||||
|
the profile proposed; no weakened rare-class conjunction is approved.
|
||||||
|
|
||||||
|
Evidence and cross-plan priorities: [estate review](../history/2026-09-28-open-workplan-infrastructure-review.md).
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue