Skip to content

Commit f861f3c

Browse files
authored
Complete the first-country configuration product (#508)
Deliver the Phase 1-3 first-country configuration model, generated product inputs, governed journeys, safe diagnostics, validation, documentation, and release evidence. All exact-head checks passed and all actionable review findings were addressed. Signed-off-by: Jeremi <9537+jeremi@users.noreply.github.com>
1 parent a4e5a89 commit f861f3c

320 files changed

Lines changed: 420007 additions & 3680 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/scripts/ci_changes.py‎

Lines changed: 226 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,179 @@
7676
".github/workflows/release-candidate-cleanup.yml",
7777
}
7878
)
79+
REPO_ROOT = Path(__file__).resolve().parents[2]
80+
STANDARD_JOURNEY_MANIFEST = (
81+
REPO_ROOT / "docs/site/src/data/standard-journeys.yaml"
82+
)
83+
AUTHORING_REFERENCE_MANIFEST = (
84+
REPO_ROOT / "docs/site/scripts/authoring-reference-sources.json"
85+
)
86+
87+
88+
def standard_journey_sources(
89+
manifest_path: Path = STANDARD_JOURNEY_MANIFEST,
90+
) -> frozenset[str]:
91+
"""Extract the exact canonical source paths from the journey manifest.
92+
93+
The manifest owns this routing inventory. Keeping the deliberately small
94+
parser here avoids adding a YAML dependency to the CI classifier.
95+
"""
96+
97+
sources: list[str] = []
98+
in_canonical_sources = False
99+
for line in manifest_path.read_text(encoding="utf-8").splitlines():
100+
if line == " canonical_sources:":
101+
in_canonical_sources = True
102+
continue
103+
if in_canonical_sources and line.startswith(" - "):
104+
source = line.removeprefix(" - ").strip()
105+
if (
106+
not source
107+
or source[0] in {"'", '"', "{", "["}
108+
or source.startswith(("/", "../"))
109+
):
110+
raise ValueError(
111+
"standard journey canonical_sources must contain "
112+
f"unquoted repository-relative paths: {source!r}"
113+
)
114+
sources.append(source)
115+
continue
116+
if in_canonical_sources and line and not line.startswith(" "):
117+
in_canonical_sources = False
118+
119+
if not sources:
120+
raise ValueError(
121+
f"no standard journey canonical_sources found in {manifest_path}"
122+
)
123+
return frozenset(sources)
124+
125+
126+
STANDARD_JOURNEY_SOURCES = standard_journey_sources()
127+
128+
129+
def authoring_reference_contract_sources(
130+
manifest_path: Path = AUTHORING_REFERENCE_MANIFEST,
131+
) -> tuple[str, ...]:
132+
"""Derive repository inputs from the published reference source contract."""
133+
134+
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
135+
schema_sources = manifest.get("schema_sources")
136+
field_knowledge = manifest.get("field_knowledge")
137+
human_intent = manifest.get("human_intent")
138+
runtime_intent = manifest.get("runtime_intent")
139+
if (
140+
not isinstance(schema_sources, list)
141+
or not schema_sources
142+
or not all(isinstance(source, str) and source for source in schema_sources)
143+
or not isinstance(field_knowledge, str)
144+
or not field_knowledge
145+
or not isinstance(human_intent, str)
146+
or not human_intent
147+
or not isinstance(runtime_intent, list)
148+
or not runtime_intent
149+
or not all(isinstance(source, str) and source for source in runtime_intent)
150+
):
151+
raise ValueError(
152+
f"authoring-reference manifest has an invalid source contract: {manifest_path}"
153+
)
154+
155+
sources = [
156+
(
157+
f"schemas/{source}"
158+
if source.startswith("registry-")
159+
else f"crates/registryctl/schemas/project-authoring/{source}"
160+
)
161+
for source in schema_sources
162+
]
163+
for source in (field_knowledge.split("#", 1)[0], human_intent):
164+
sources.append(
165+
source if source.startswith("crates/") else f"crates/registryctl/{source}"
166+
)
167+
sources.extend(runtime_intent)
168+
if any(source.startswith(("/", "../")) for source in sources):
169+
raise ValueError(
170+
"authoring-reference source contract must use repository-relative paths"
171+
)
172+
if len(sources) != len(set(sources)):
173+
raise ValueError("authoring-reference source contract paths must be unique")
174+
return tuple(sources)
175+
176+
177+
def validate_authoring_reference_routing(
178+
contract_sources: tuple[str, ...],
179+
inputs: tuple[tuple[str, str], ...],
180+
) -> None:
181+
"""Fail when a source-contract input can change without rebuilding docs."""
182+
183+
missing = [
184+
source
185+
for source in contract_sources
186+
if not any(fnmatch.fnmatchcase(source, pattern) for pattern, _ in inputs)
187+
]
188+
if missing:
189+
raise ValueError(
190+
"authoring-reference CI inputs do not route source-contract paths: "
191+
f"{missing}"
192+
)
193+
194+
195+
def authoring_reference_inputs(
196+
manifest_path: Path = AUTHORING_REFERENCE_MANIFEST,
197+
) -> tuple[tuple[str, str], ...]:
198+
"""Load the authoring-reference CI routing inventory from its owner."""
199+
200+
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
201+
inputs = manifest.get("ci_inputs")
202+
if not isinstance(inputs, list) or not inputs:
203+
raise ValueError(
204+
f"authoring-reference manifest has no ci_inputs: {manifest_path}"
205+
)
206+
207+
parsed: list[tuple[str, str]] = []
208+
for index, entry in enumerate(inputs):
209+
if not isinstance(entry, dict):
210+
raise ValueError(
211+
f"authoring-reference ci_inputs[{index}] must be an object"
212+
)
213+
pattern = entry.get("pattern")
214+
sample = entry.get("sample")
215+
if (
216+
not isinstance(pattern, str)
217+
or not pattern
218+
or not isinstance(sample, str)
219+
or not sample
220+
or pattern.startswith(("/", "../"))
221+
or sample.startswith(("/", "../"))
222+
or not fnmatch.fnmatchcase(sample, pattern)
223+
):
224+
raise ValueError(
225+
"authoring-reference CI inputs must have matching "
226+
f"repository-relative pattern/sample pairs: {entry!r}"
227+
)
228+
if not (REPO_ROOT / sample).is_file():
229+
raise ValueError(
230+
"authoring-reference CI input samples must name existing "
231+
f"repository files: {sample!r}"
232+
)
233+
parsed.append((pattern, sample))
234+
235+
patterns = [pattern for pattern, _ in parsed]
236+
samples = [sample for _, sample in parsed]
237+
if len(patterns) != len(set(patterns)) or len(samples) != len(set(samples)):
238+
raise ValueError("authoring-reference CI patterns and samples must be unique")
239+
result = tuple(parsed)
240+
validate_authoring_reference_routing(
241+
authoring_reference_contract_sources(manifest_path),
242+
result,
243+
)
244+
return result
245+
246+
247+
AUTHORING_REFERENCE_CONTRACT_SOURCES = authoring_reference_contract_sources()
248+
AUTHORING_REFERENCE_INPUTS = authoring_reference_inputs()
249+
AUTHORING_REFERENCE_PATTERNS = tuple(
250+
pattern for pattern, _ in AUTHORING_REFERENCE_INPUTS
251+
)
79252

80253

81254
class Workspace:
@@ -256,12 +429,42 @@ def classify(
256429
path,
257430
"crates/registry-relay/docs/*",
258431
"crates/registry-relay/openapi/*",
432+
"crates/registry-relay/src/api/openapi.rs",
433+
"crates/registryctl/assets/project-starters/*",
434+
"crates/registry-notary-server/src/standalone/activation.rs",
435+
"crates/registry-platform-ops/src/lib.rs",
436+
"crates/registry-relay/src/consultation/*",
437+
"crates/registryctl/schemas/project-reports/*",
438+
"crates/registryctl/src/templates/*",
439+
"crates/registryctl/tests/fixtures/project-authoring/*",
440+
"crates/registryctl/tests/fixtures/project-reports/*",
259441
"docs/site/*",
260442
"products/manifest/docs/*",
261443
"products/notary/docs/*",
262444
"products/notary/openapi/*",
445+
*AUTHORING_REFERENCE_PATTERNS,
263446
)
264-
or path == ".github/workflows/docs-pages.yml"
447+
or path
448+
in {
449+
".github/workflows/docs-pages.yml",
450+
"crates/registry-relay/src/main.rs",
451+
"crates/registry-relay/src/process_startup.rs",
452+
"crates/registry-relay/src/server.rs",
453+
"crates/registryctl/src/main.rs",
454+
"crates/registryctl/src/project_authoring/capability_inventory.rs",
455+
"crates/registryctl/src/project_authoring/diagnostic_reference.rs",
456+
"crates/registryctl/src/project_authoring/diagnostics.rs",
457+
"crates/registryctl/src/project_authoring/fixture_diagnostics.rs",
458+
"crates/registryctl/src/project_authoring/fixture_coverage.rs",
459+
"crates/registryctl/src/project_authoring/migration.rs",
460+
"crates/registryctl/src/project_authoring/output.rs",
461+
"crates/registryctl/src/project_authoring/preflight.rs",
462+
"crates/registryctl/src/project_authoring/promotion.rs",
463+
"crates/registryctl/src/project_authoring/report_contract.rs",
464+
"crates/registryctl/src/project_authoring/semantic_comparison.rs",
465+
"crates/registryctl/tests/fixtures/project-authoring-journeys.yaml",
466+
}
467+
or path in STANDARD_JOURNEY_SOURCES
265468
for path in paths
266469
)
267470
docs_archives = any(
@@ -310,8 +513,29 @@ def classify(
310513
or path.startswith("products/notary/")
311514
for path in paths
312515
)
516+
tutorial_source_under_test = any(
517+
matches(
518+
path,
519+
"crates/registry-notary/src/*",
520+
"crates/registry-notary-core/src/*",
521+
"crates/registry-notary-server/src/*",
522+
"crates/registryctl/src/templates/*",
523+
)
524+
or path
525+
in {
526+
"crates/registry-relay/src/api/openapi.rs",
527+
"crates/registry-relay/src/main.rs",
528+
"crates/registry-relay/src/server.rs",
529+
"crates/registryctl/src/main.rs",
530+
"crates/registryctl/src/project_authoring/output.rs",
531+
}
532+
for path in paths
533+
)
313534
registryctl_tutorial = (
314-
complete or tutorial_infrastructure or bool(affected & TUTORIAL_PACKAGES)
535+
complete
536+
or tutorial_infrastructure
537+
or tutorial_source_under_test
538+
or bool(affected & TUTORIAL_PACKAGES)
315539
)
316540

317541
matrix = []

0 commit comments

Comments
 (0)