Skip to content

Commit 0a539ce

Browse files
committed
Repair plugin API dependency coordinate
1 parent e2d7743 commit 0a539ce

30 files changed

Lines changed: 1299 additions & 8 deletions

.github/workflows/test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,8 @@ jobs:
2929
java -version
3030
sbt -batch verifyJdkVersionEnforcement
3131
32+
- name: Verify build dependency coordinates
33+
run: sbt -batch verifyBuildDependencyCoordinatePolicy
34+
3235
- name: Run tests
3336
run: sbt test

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Useful project docs:
2929
- [Generated-origin position feasibility history](docs/quasiquotes-generated-origin-position-contract-feasibility.md)
3030
- [Experimental API surface](docs/experimental-api-surface.md)
3131
- [Experimental plugin API surface baseline](docs/experimental-plugin-api-surface-baseline.md)
32+
- [`pluginApi` dependency-coordinate integrity](docs/plugin-api-dependency-coordinate-integrity.md)
3233
- [Precompiled handler execution and output contract](docs/precompiled-handler-execution-and-output-contract.md)
3334
- [Structured expansion output role contract](docs/structured-expansion-output-role-contract.md)
3435
- [Annotated-class shape and admission contract](docs/annotated-class-shape-and-admission-contract.md)
@@ -189,6 +190,18 @@ the pinned experimental build, not stable API, cross-version compatibility,
189190
artifact publication, or release policy. See the
190191
[experimental plugin API surface baseline](docs/experimental-plugin-api-surface-baseline.md).
191192

193+
Prompt 78 repairs the `pluginApi` compiler dependency organization to exactly
194+
`org.scala-lang`. `verifyBuildDependencyCoordinatePolicy` checks the effective
195+
sbt declarations, exact compiler/version/scope, toolchain pins, root aggregate,
196+
and retained Prompt 77 verifier in 14 bounded cases.
197+
`verifyPluginApiCleanResolution` then copies the target-free repository to a
198+
disposable directory, resolves with fresh task-owned Coursier/Ivy state,
199+
compiles and packages `pluginApi`, audits the thin JAR, and deletes the copy and
200+
cache. The clean package remains 175956 bytes, 126 entries, and SHA-256
201+
`f5221f7bb27586f9994b4daca420676ade624c40a67f54f3fe8aa71de411be79`;
202+
the Prompt 77 surface SHA remains unchanged. See
203+
[`pluginApi` dependency-coordinate integrity](docs/plugin-api-dependency-coordinate-integrity.md).
204+
192205
Before either direct splicing or a composition-state update, the plugin
193206
validates both successful forms. Structured output receives null-safe role,
194207
kind, uniqueness, and package-conflict validation, is canonicalized, and then

ROADMAP.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,9 +493,28 @@ and missing-API negative compiles fail without output. This checkpoint does not
493493
promise stable or cross-version compatibility, Maven publication, semantic
494494
versioning, or release readiness.
495495

496-
The next bounded decision must be driven by a concrete packaged-consumer,
497-
classloader, or authoring problem. Do not add another generic adapter or promote
498-
the exact-build manifest into a public compatibility promise automatically.
496+
Controller review then found that Prompt 77 had committed an invalid
497+
prompt-contaminated organization for the `pluginApi` compiler dependency.
498+
Prompt 78 repairs that coordinate and establishes:
499+
500+
```text
501+
PLUGIN_API_DEPENDENCY_COORDINATE_REPAIRED
502+
PLUGIN_API_CLEAN_RESOLUTION_AND_PACKAGE_PROVEN
503+
EXPERIMENTAL_PLUGIN_API_SURFACE_BASELINE_RESTORED
504+
```
505+
506+
The effective-coordinate policy passes 14/14 cases. A target-free disposable
507+
copy resolves the exact `org.scala-lang:scala3-compiler_3` dependency through a
508+
fresh task-owned cache, clean-compiles and packages the API, reproduces the
509+
175956-byte/126-entry JAR and SHA-256
510+
`f5221f7bb27586f9994b4daca420676ade624c40a67f54f3fe8aa71de411be79`,
511+
and deletes both repository copy and cache. The canonical Prompt 77 manifest
512+
remains byte-identical with normalized SHA-256
513+
`039a25870ed7265a657bb5262f86e0af13a35672f942db7a81d4ba66184217e0`.
514+
515+
Only after this repair may the next bounded broad-vs-small experimental API
516+
decision resume. Do not add another generic adapter or promote the exact-build
517+
manifest into a public compatibility promise automatically.
499518

500519
## Known Risks
501520

bootstrap-prompt.md

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ The current project state is a minimal Scala 3 research compiler-plugin project
110110
manual dispatch or Sunday 04:17 UTC schedule, keeps failures visible, has
111111
read-only permissions, uploads 14-day bounded evidence, and never runs on
112112
push, pull request, or merge. The ordinary pinned `Test` workflow remains
113-
byte-identical.
113+
blocking; Prompt 78 adds only its required local dependency-coordinate gate
114+
before the main tests and refreshes the policy-owned workflow hash.
114115
- `project/RecurringExactNightlyWorkflowPolicy.scala`,
115116
`project/RecurringExactNightlyWorkflowPolicySpec.scala`, and
116117
`verifyRecurringExactNightlyWorkflowPolicy` make the workflow and invariant
@@ -134,6 +135,12 @@ The current project state is a minimal Scala 3 research compiler-plugin project
134135
handler linkage probes. Classification is
135136
`EXPERIMENTAL_PLUGIN_API_SURFACE_BASELINE_READY`; it is not a stable API or
136137
cross-version compatibility promise.
138+
- Prompt 78 repairs the invalid prompt-contaminated `pluginApi` compiler
139+
organization to `org.scala-lang`, adds a 14-case effective-coordinate policy,
140+
and proves target-free/fresh-cache resolution and packaging. Classifications
141+
are `PLUGIN_API_DEPENDENCY_COORDINATE_REPAIRED`,
142+
`PLUGIN_API_CLEAN_RESOLUTION_AND_PACKAGE_PROVEN`, and
143+
`EXPERIMENTAL_PLUGIN_API_SURFACE_BASELINE_RESTORED`.
137144
- The build adds `Resolver.scalaNightlyRepository` because research plugins are only enabled on nightly or snapshot Scala 3 builds.
138145
- The plugin defines custom built-in marker annotations in `paradise3.gen` and `paradise3.debug`.
139146
- The experimental handler API defines `paradise3.api.expander`, a tiny `paradise3.api.helpers.ExpansionHelpers` convenience layer, `paradise3.externalDebug`, `paradise3.externalCompanionDebug`, `paradise3.externalSiblingDebug`, `paradise3.externalLabel`, `paradise3.externalTypedLabel`, `paradise3.externalMarker`, and fixture-only `paradise3.externalQuasiquotesTerm` in `pluginApi` for the precompiled external-handler loading spikes.
@@ -733,6 +740,12 @@ Create these files:
733740
222. `docs/experimental-plugin-api-surface-baseline.md`
734741
223. `prompts/77.codex.experimental.plugin.api.surface.baseline.and.isolated.handler.linkage.contract.prompt.md`
735742
224. `reviews/77_chatgpt_experimental_plugin_api_surface_baseline_handoff/README.md`
743+
225. `project/BuildDependencyCoordinatePolicy.scala`
744+
226. `project/BuildDependencyCoordinatePolicySpec.scala`
745+
227. `project/PluginApiCleanResolution.scala`
746+
228. `docs/plugin-api-dependency-coordinate-integrity.md`
747+
229. `prompts/78.codex.plugin.api.dependency.coordinate.repair.and.clean.resolution.proof.prompt.md`
748+
230. `reviews/78_chatgpt_plugin_api_dependency_coordinate_repair_handoff/README.md`
736749

737750
## File Requirements
738751

@@ -2344,8 +2357,10 @@ Create these files:
23442357
`verifyJdkVersionEnforcement`, and exactly one
23452358
`verifyNewerExactNightlyCompatibility` command. Never duplicate the ladder or
23462359
put the exact Scala version/discovery logic in YAML.
2347-
- Keep the normal `.github/workflows/test.yml` byte-identical and blocking for
2348-
push/PR. The recurring workflow is non-blocking because it has no
2360+
- Keep the normal `.github/workflows/test.yml` pinned and blocking for push/PR,
2361+
including Prompt 78's dependency-coordinate policy before the main tests.
2362+
Refresh its policy-owned hash only when a separately reviewed task changes
2363+
that workflow. The recurring workflow is non-blocking because it has no
23492364
push/PR/merge trigger, while its failures remain visible.
23502365
- Keep the recurring workflow policy model/spec/task and its synthetic drift
23512366
checks. Preserve the exact descriptor and hashes, root Scala, sbt, JDK,
@@ -2448,6 +2463,32 @@ Create these files:
24482463
drift evidence, not stable/cross-version compatibility, semantic versioning,
24492464
Maven publication, or release policy.
24502465

2466+
### Prompt 78 and review handoff
2467+
2468+
- Keep the `pluginApi` compiler dependency exactly
2469+
`"org.scala-lang" %% "scala3-compiler" % scalaVersion.value`. Historical
2470+
Prompt 78 evidence may quote the bad organization, but production settings,
2471+
current policy, manifests, and current documentation must not treat it as a
2472+
valid coordinate.
2473+
- Keep `BuildDependencyCoordinatePolicy` and its 14-case spec bounded to the
2474+
effective `pluginApi` compiler coordinate, prompt-number contamination,
2475+
pinned Scala/sbt/JDK policy, separate project, five-member root aggregate,
2476+
and retained Prompt 77 manifest/tasks.
2477+
- Keep `verifyBuildDependencyCoordinatePolicy` in the ordinary pinned `Test`
2478+
workflow before the main tests. It is local and deterministic.
2479+
- Keep `verifyPluginApiCleanResolution` explicit. It must copy no `.git` or
2480+
target/IDE/workspace state, use task-owned fresh Coursier and isolated Ivy/sbt
2481+
state, run the clean update/compile/package sequence, audit the thin JAR, and
2482+
delete both disposable repository and cache.
2483+
- Keep `docs/plugin-api-dependency-coordinate-integrity.md` and
2484+
`reviews/78_chatgpt_plugin_api_dependency_coordinate_repair_handoff/` as the
2485+
focused contract and exact 19-document evidence packet.
2486+
- Preserve `PLUGIN_API_DEPENDENCY_COORDINATE_REPAIRED`,
2487+
`PLUGIN_API_CLEAN_RESOLUTION_AND_PACKAGE_PROVEN`, and
2488+
`EXPERIMENTAL_PLUGIN_API_SURFACE_BASELINE_RESTORED`. They repair and restore
2489+
exact-build evidence; they do not promote the API or choose the next
2490+
broad-vs-small design.
2491+
24512492
### `bootstrap-prompt.md`
24522493

24532494
- Describe the repository as a minimal Scala 3 research compiler-plugin project
@@ -2510,6 +2551,9 @@ Create these files:
25102551
- Include Prompt 77's canonical manifest, verifier/model spec, candidate-render
25112552
and verification tasks, isolated positive/runtime/negative source probes,
25122553
focused baseline document, prompt, and exact 20-document handoff.
2554+
- Include Prompt 78's corrected compiler coordinate, dependency policy/spec,
2555+
clean-resolution task, ordinary Test workflow gate, focused integrity
2556+
document, prompt, and exact 19-document handoff.
25132557
- Explain that the document must evolve with the repository as new files and behavior are introduced.
25142558

25152559
## Constraints

build.sbt

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ lazy val renderExperimentalPluginApiSurfaceBaseline =
8181
lazy val verifyExperimentalPluginApiSurfaceBaseline =
8282
taskKey[Unit]("Verify the exact-build pluginApi surface and isolated handler linkage contract")
8383

84+
lazy val verifyBuildDependencyCoordinatePolicy =
85+
taskKey[Unit]("Verify the exact pluginApi dependency coordinate and retained build shape")
86+
87+
lazy val verifyPluginApiCleanResolution =
88+
taskKey[Unit]("Verify pluginApi resolution and packaging from a target-free fresh dependency cache")
89+
8490
lazy val root = (project in file("."))
8591
.aggregate(
8692
legacyMetadataMarkerFixture,
@@ -260,8 +266,122 @@ lazy val sameModuleHandlerCycleSpike =
260266
lazy val pluginApi = (project in file("plugin-api"))
261267
.settings(
262268
name := "macroparadise-scala3-plugin-api",
263-
libraryDependencies += "orgP069.scala-lang" %% "scala3-compiler" % scalaVersion.value
269+
libraryDependencies += "org.scala-lang" %% "scala3-compiler" % scalaVersion.value
270+
)
271+
272+
verifyBuildDependencyCoordinatePolicy := {
273+
BuildDependencyCoordinatePolicySpec.run()
274+
JdkVersionEnforcement.enforceCurrent()
275+
276+
def dependency(module: ModuleID): BuildDependencyCoordinatePolicy.Dependency =
277+
BuildDependencyCoordinatePolicy.Dependency(
278+
module.organization,
279+
module.name,
280+
module.revision,
281+
module.configurations.getOrElse("compile"),
282+
module.explicitArtifacts.flatMap(_.classifier).toList
283+
)
284+
285+
val structure = buildStructure.value
286+
val rootRef = thisProjectRef.value
287+
val rootBuildRefs = structure.allProjectRefs.filter(_.build == rootRef.build)
288+
val extracted = Project.extract(state.value)
289+
val allDependencies = rootBuildRefs.flatMap { reference =>
290+
extracted.getOpt(reference / libraryDependencies).getOrElse(Seq.empty)
291+
}
292+
val rootProject =
293+
structure.allProjectPairs.find(_._2 == rootRef).map(_._1).getOrElse {
294+
sys.error(s"root project ${rootRef.project} is missing from the loaded build")
295+
}
296+
val pluginApiRef = rootBuildRefs.find(_.project == "pluginApi").getOrElse {
297+
sys.error("pluginApi project is missing from the loaded build")
298+
}
299+
val pluginApiProject =
300+
structure.allProjectPairs.find(_._2 == pluginApiRef).map(_._1).getOrElse {
301+
sys.error("pluginApi project definition is missing from the loaded build")
302+
}
303+
val expectedPluginApiBase = (baseDirectory.value / "plugin-api").getCanonicalFile
304+
val shape = BuildDependencyCoordinatePolicy.BuildShape(
305+
scalaVersion.value,
306+
sbtVersion.value,
307+
JdkVersionEnforcement.currentDetectedVersion().feature.getOrElse(-1),
308+
pluginApiProject.id,
309+
pluginApiRef != rootRef && pluginApiProject.base.getCanonicalFile == expectedPluginApiBase,
310+
rootProject.aggregate.map(_.project).toSet,
311+
(baseDirectory.value / "project" / "experimental-plugin-api-surface-baseline.txt").isFile,
312+
Set(
313+
renderExperimentalPluginApiSurfaceBaseline.key.label,
314+
verifyExperimentalPluginApiSurfaceBaseline.key.label
315+
)
264316
)
317+
val result = BuildDependencyCoordinatePolicy.verify(
318+
(pluginApi / libraryDependencies).value.map(dependency),
319+
allDependencies.map(dependency),
320+
shape
321+
)
322+
require(
323+
result.errors.isEmpty,
324+
s"build dependency-coordinate policy failed: ${result.errors.mkString("; ")}"
325+
)
326+
streams.value.log.info(
327+
s"build dependency-coordinate policy verified: ${result.render} syntheticCases=${BuildDependencyCoordinatePolicySpec.CaseCount}/${BuildDependencyCoordinatePolicySpec.CaseCount}"
328+
)
329+
}
330+
331+
verifyPluginApiCleanResolution := {
332+
def dependency(module: ModuleID): BuildDependencyCoordinatePolicy.Dependency =
333+
BuildDependencyCoordinatePolicy.Dependency(
334+
module.organization,
335+
module.name,
336+
module.revision,
337+
module.configurations.getOrElse("compile"),
338+
module.explicitArtifacts.flatMap(_.classifier).toList
339+
)
340+
341+
val structure = buildStructure.value
342+
val rootRef = thisProjectRef.value
343+
val rootBuildRefs = structure.allProjectRefs.filter(_.build == rootRef.build)
344+
val extracted = Project.extract(state.value)
345+
val allDependencies = rootBuildRefs.flatMap { reference =>
346+
extracted.getOpt(reference / libraryDependencies).getOrElse(Seq.empty)
347+
}
348+
val rootProject = structure.allProjectPairs.find(_._2 == rootRef).map(_._1).get
349+
val pluginApiRef = rootBuildRefs.find(_.project == "pluginApi").get
350+
val pluginApiProject = structure.allProjectPairs.find(_._2 == pluginApiRef).map(_._1).get
351+
val shape = BuildDependencyCoordinatePolicy.BuildShape(
352+
scalaVersion.value,
353+
sbtVersion.value,
354+
JdkVersionEnforcement.currentDetectedVersion().feature.getOrElse(-1),
355+
pluginApiProject.id,
356+
pluginApiProject.base.getCanonicalFile == (baseDirectory.value / "plugin-api").getCanonicalFile,
357+
rootProject.aggregate.map(_.project).toSet,
358+
(baseDirectory.value / "project" / "experimental-plugin-api-surface-baseline.txt").isFile,
359+
Set(
360+
renderExperimentalPluginApiSurfaceBaseline.key.label,
361+
verifyExperimentalPluginApiSurfaceBaseline.key.label
362+
)
363+
)
364+
val result = PluginApiCleanResolution.run(
365+
baseDirectory.value,
366+
target.value / "plugin-api-clean-resolution",
367+
(pluginApi / libraryDependencies).value.map(dependency),
368+
allDependencies.map(dependency),
369+
shape
370+
)
371+
require(
372+
result.classification != PluginApiCleanResolution.FailedClassification,
373+
s"pluginApi clean resolution proof failed: ${result.render}"
374+
)
375+
require(
376+
result.disposableRepositoryDeleted && result.taskOwnedCacheDeleted,
377+
s"pluginApi clean resolution proof did not delete disposable state: ${result.render}"
378+
)
379+
val log = streams.value.log
380+
if (result.isBlocked)
381+
log.warn(s"pluginApi clean resolution proof environmentally blocked: ${result.render}")
382+
else
383+
log.info(s"pluginApi clean resolution verified: ${result.render}")
384+
}
265385

266386
renderExperimentalPluginApiSurfaceBaseline := {
267387
val evidence = target.value / "experimental-plugin-api-surface-baseline-render"

docs/experimental-plugin-api-surface-baseline.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ and regression-detectable. It does not declare a stable public API, general
1111
binary compatibility, release readiness, or compatibility across Scala
1212
versions.
1313

14+
Prompt 78 controller review found that the original Prompt 77 commit contained
15+
an invalid compiler dependency organization. The original local passes
16+
therefore did not establish clean resolution reproducibility. Prompt 78
17+
corrects the organization to `org.scala-lang`, adds an effective-coordinate
18+
policy, and proves the same package from a target-free disposable copy and a
19+
fresh task-owned dependency cache. The canonical surface records and normalized
20+
SHA below remain unchanged, so the baseline classification is restored rather
21+
than regenerated. See
22+
[`pluginApi` dependency-coordinate integrity](plugin-api-dependency-coordinate-integrity.md).
23+
1424
The baseline is valid only for:
1525

1626
```text

0 commit comments

Comments
 (0)