CXF-220: pre-1 design and spec-sourcing skills for net-new connector providers - #14
Conversation
…pec) + park-vs-proceed eval measurement - Two new pre-1 skills (design-access-model, source-openapi-spec) with SOURCES.md pins; bundle v0.3.0 (7 skills); orchestrator routing split. - Fixture no-IAM surface: openapi-noiam.json + /noiam/openapi.json route + verify.sh checks 17-19 (all 19 assertions). - Runner pre1 kind: scenario kind/validation, P0-P4 gates, scoreRun branch with decision_verdict/decision_evidence, readPre1Artifact, pre1 main branch, baseline S0-first skip, tier0 canned-dir selection. - Two pre1 scenarios + canned replay sets; unit smokes in existing tests. Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
…y gate, canned fidelity, hygiene Adversarial review round 1 (A1-A6, P1-P4) found the pre1 production path (readPre1Artifact + main() pre1 branch + pre1 prompt) had zero committed test coverage — a regression there silently corrupts the park-vs-proceed metric. Fixes: - run.test.ts: readPre1Artifact unit cases (oversized/malformed/non-object -> null, valid -> parsed) + two CLI-level pre1 Tier-0 replays asserting the written record carries decision_verdict and the P-stage rows. - agent.test.ts: pre1 prompt case (pre1Path, both skills, output contract). - stages.ts: P2 gate now fails on malformed extra entries instead of filtering them out before the set-compare (gate contract: a malformed artifact fails its gate); stages.test.ts locks it. - run.ts: extract shared readBoundedJson used by readHandoff and readPre1Artifact (the two had already drifted); placeholder scrub stays in the handoff caller. - canned-pre1-noiam-park/transcript.json: wc -c 12297 -> 4997 (the real size of openapi-noiam.json; the proceed set's byte count was copied). - Re-indent ~9 statements dedented to column 0 across run.ts, driver.ts, scenario.ts, skills_bundle.test.ts, server.ts. Validation: typecheck, eval:test (133 pass), eval:verify (19 assertions), and the three eval:run Tier-0 replays (proceed P0-P3, park P0/P1/P4, funnel S0-S11) all exit 0. Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
General PR Review: CXF-220: pre-1 design and spec-sourcing skills for net-new connector providersBlocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0 Review SummaryThe new commit addresses both prior findings: P4 now enforces Security IssuesNone found. Correctness IssuesNone found. Suggestions
Prompt for AI agents |
…ions, canned-dir guard, funnel score-input ENOENT, bundle version guard, pre1 metric docs Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
…t, tier0 guard tests, drop dead readBundle Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
…pe, drop dead pre1 score-input write, single-source skillBundle validation, document driver contract Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
|
Round-3 suggestions addressed in 2823a29: (1) baseline.ts skip predicate narrowed to the pre-1 shape (P-led stages) so corrupt funnel records missing S0 still fail the canonical-row check; (2) the dead pre-1 score-input.json write and the two canned-pre1-*/score-input.json files deleted (run.ts builds its own ScoreInput literal on the pre-1 path); (3) skillBundle validation + bundle-version drift check extracted into a single parseSkillBundle(data) helper called by both branches; (4) drivers/README.md updated — RunChannel bullet lists pre1Path/pre1Instructions (with the two-halves contract), AgentDriver bullet documents scenarioId/scenarioKind, and the run-channel obligations add the pre1 rule (write to channel.pre1Path, skip the collector leg). Verified: typecheck + 134/134 tests green, fixture verify 19/19, all three Tier-0 replays green. |
…er-skill version source - P4 now compares the artifact's spec_version_checked against the scenario's expectedParkEvidence and requires every expected missing path to be present (superset allowed), so a park run with generic boilerplate evidence no longer scores a perfect P0/P1/P4. - bundle.json entries carry the per-skill version; the bundle test asserts each SKILL.md frontmatter version against its bundle entry instead of a test-local SKILL_VERSIONS constant, keeping bundle.json the single source for version provenance. Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
| const expected = ctx.expected?.parkEvidence | ||
| if (expected === undefined) return false | ||
| if (pe.spec_version_checked !== expected.spec_version_checked) return false | ||
| return expected.missing_paths.every((p) => pe.missing_paths.includes(p)) |
There was a problem hiding this comment.
🟡 Suggestion: evidence() below was not updated for the new expected-comparison, so a run that fails P4 only on spec_version_checked mismatch or a missing expected path still reports spec_version_checked=set, missing_paths=3, vendor_doc=set, revisit_trigger=set — a fail row with no visible reason. P2 already reports match/mismatch per dimension; adding spec_version=match|mismatch and the count of expected paths not found would make P4 failures diagnosable from the record alone. (confidence: high, non-blocking)
| // the checked spec version must match exactly and every expected missing | ||
| // path must be present (the artifact may list more). | ||
| const expected = ctx.expected?.parkEvidence | ||
| if (expected === undefined) return false |
There was a problem hiding this comment.
🟡 Suggestion: expected === undefined now hard-fails P4, but loadScenario only enforces that exactly one of expectedAccessModel/expectedParkEvidence is present (scenario.ts:242-246) — it never ties that choice to expectedDecision. A scenario with expectedDecision: "park" plus expectedAccessModel still loads, then scores P4 as an unconditional fail at run time with evidence showing every field set. Rejecting the mismatched pairing in the loader (park ⇒ expectedParkEvidence, proceed ⇒ expectedAccessModel) would turn that into a load-time error. (confidence: medium, non-blocking)
| {"name": "write-connector-source", "path": "../../skills/write-connector-source/SKILL.md"}, | ||
| {"name": "build-and-test", "path": "../../skills/build-and-test/SKILL.md"}, | ||
| {"name": "deploy-and-activate", "path": "../../skills/deploy-and-activate/SKILL.md"} | ||
| {"name": "author-in-app-connector", "version": "0.2.1", "path": "../../skills/author-in-app-connector/SKILL.md"}, |
There was a problem hiding this comment.
🟡 Suggestion: moving per-skill versions into the manifest closes the "versions live only in a test constant" gap, but the run record still stamps only the top-level version (buildRunMeta → scenario.skillBundle.version), and nothing forces that top-level bump when a per-skill entry changes. Bumping design-access-model to 0.1.1 (body + frontmatter + this entry) keeps every test green and still stamps records 0.3.0, so two runs with different skill bodies remain indistinguishable in the results. Deriving/asserting the bundle version from the skill entries, or recording the per-skill versions in the record meta, would close it. Separately: the new version field isn't described in evals/skills-bundle/README.md, whose mount contract still says the scenario pins 0.2.0, and its "the five funnel skills are unchanged" line no longer holds now that author-in-app-connector is 0.2.1 with a modified body. (confidence: medium, non-blocking)
Summary
Net-new connector providers need two judgment steps before any source is written: decide whether the provider's API actually has an IAM surface worth connecting, and design the access model (resource types, traits, entitlements, grants) from the sourced spec. This PR ships those two steps as agent skills —
design-access-modelandsource-openapi-spec— and makes the eval harness measure the park-vs-proceed decision separately from the rest of the funnel, so a provider that should be parked (no member-listing API) is scored on the quality of its park evidence, not on a connector that was never built.Linear
CXF-220: CXF-70 PR 5: design + spec sourcing skills (3, 4)
Linear requirements
This PR meets all requirements of CXF-220.
design-access-modelskill: API → resource types/traits/entitlements/grants, stable-ID rules, sync-only-vs-provisionable with mandatory "because the API lacks X" justification, ID-compatibility output contract, port minus repo assumptions,WithExternalIDDEPRECATEDskills/design-access-model/SKILL.mdL1-90 (decision tables L21-44, stable-ID rules L46-49, output contract L56-64, anti-patterns L79-84)source-openapi-specskill: 5-rung authority ladder, IAM go/no-go gate, park-with-evidence success outcome, in-app spec-weight twist (262144/1048576 caps)skills/source-openapi-spec/SKILL.mdL1-81 (ladder L14-32, go/no-go gate L34-47, spec-weight L49-54, output contract L56-61)skills/design-access-model/SKILL.mdL21-44 (tables a/b/c)evals/runner/stages.tsL358+ (P1 gatedecision === expectedDecision),evals/runner/score.tsL167-200 (decision_verdict/decision_evidence),evals/runner/record.tsL37evals/scenarios/pre1-directory-proceed.json,evals/scenarios/pre1-noiam-park.json,evals/fixture/openapi-noiam.json, Tier-0 canned replays inevals/runner/drivers/tier0/canned-pre1-*/Release Notes
No user-facing change.
What changed
skills/design-access-model/SKILL.md(new)Where: whole file, L1-90.
What changed
access_modelhalf of the pre1.json output contract.design-baton-access-modelminus repo assumptions; handoffs repoint to in-app skills (source-openapi-spec,write-connector-source).Why
skills/source-openapi-spec/SKILL.md(new)Where: whole file, L1-81.
What changed
wc -cthe spec and record bytes against the 262144-byte source / 1048576-byte bundle caps.source-openapi-specskill; emits thesourcingandpark_evidencehalves of the pre1.json artifact.Why
skills/design-access-model/SOURCES.md,skills/source-openapi-spec/SOURCES.md(new)Where: whole files.
What changed
6fe6886f…, claude-marketplace0cc5ac2a…, c116e0e0fb…, in-repo SDK at7dc673ac…).Why
skills/author-in-app-connector/SKILL.mdWhere: routing table L93-94, new Pre-S1 checklist L100-103, frontmatter version L4.
What changed
pre-1 design (net-new provider)→design-access-model,pre-1 spec sourcing→source-openapi-spec; added a pre-S1 checklist note; version bumped 0.2.0 → 0.2.1.Why
skills/README.mdWhere: table L14-15, header L3.
What changed
Why
evals/fixture/openapi-noiam.json(new)Where: whole file, 223 lines.
What changed
Why
evals/fixture/server.tsWhere: L23 (load), L175-186 (route).
What changed
GET /noiam/openapi.json, unauthenticated, same pattern as/openapi.json.Why
evals/fixture/verify.shWhere: L164-178 (assertions 17-19).
What changed
/noiam/openapi.jsonreturns 200, serves/v1/me, and has no/v1/usersor/v1/groupspaths. 16 → 19 checks.Why
evals/runner/scenario.tsWhere:
Scenariointerface L31-70, kind dispatch L140-145, funnel branch L145-228, pre1 branch L230-355.What changed
kind("funnel"default |"pre1"); pre1 scenarios carryproviderBrief,expectedDecision, and exactly one ofexpectedAccessModel/expectedParkEvidence; funnel-only fields (seed,expected,requiredSourceFiles) are rejected for pre1; both expected halves are shape-validated at load time.Why
evals/runner/stages.tsWhere:
StageCtxpre1 fields L40-45,Pre1Artifacttypes L48-70,PRE1_STAGESL358-527.What changed
id_compatibility; every provisioning entry justified with a booleanprovisionable), P3 sourcing provenance (spec_bytespositive integer < 1048576), P4 park evidence (all four fields non-empty,missing_pathsnon-empty array). Every check type-checks the untrusted artifact defensively and never throws.Why
evals/runner/score.tsWhere:
ScoreResultL25-27, pre1 branch L167-200.What changed
scoreRunbranches onkind === "pre1": scoresPRE1_STAGES, setsdecision_verdictto the expected decision when P1 passes and"incorrect"otherwise, and reports parity/hygiene as "not applicable (pre1 run)".Why
evals/runner/run.tsWhere:
readBoundedJsonL118-160,readPre1ArtifactL178-184, channelpre1PathL201, pre1 run path L376-425.What changed
readPre1Artifactfor the pre1 artifact; the pre1 run path reads the artifact, skips the collector leg, scores P0-P4, and writes the record withdecision_verdict.Why
evals/runner/agent.tsWhere: pre1 prompt branch L18-38.
What changed
buildPromptreturns a pre1 prompt: run the two pre-1 skills in order, fetch the spec, writepre1.jsonto the channel'spre1Pathwith the output contract, thendriver.complete_run.Why
evals/runner/baseline.tsWhere: L77-88.
What changed
Why
evals/results/locally without breaking baseline generation; funnel-shaped records still validate exactly as before.evals/runner/driver.tsWhere:
RunChannel.pre1PathL63,AgentRunRequest.scenarioIdL75-76.What changed
pre1Path; the agent request carries an optionalscenarioIdfor canned-set selection.Why
evals/runner/drivers/tier0/driver.tsWhere:
waitForSpecL89-104, provisioner meta L125-151, canned-dir selection L170-196.What changed
runAgentselectscanned-<scenarioId>/when it exists (pre1 replays) and falls back to the fixed funnel set; writespre1.json/score-input.jsonfrom the selected set.Why
evals/runner/record.tsWhere:
SummaryLineL36-38.What changed
decision_verdict/decision_evidencesummary fields.Why
evals/scenarios/pre1-directory-proceed.json,evals/scenarios/pre1-noiam-park.json(new)Where: whole files.
What changed
proceedwith the expected access model) and Acme Analytics with no IAM API (expected decisionparkwith the expected park evidence). Both pinskillBundle {mode: "full", version: "0.3.0"}and the tier1 model/effort pins.Why
evals/runner/drivers/tier0/canned-pre1-directory-proceed/,evals/runner/drivers/tier0/canned-pre1-noiam-park/(new)Where:
transcript.json,pre1.json,score-input.jsonin each.What changed
pre1.jsonviadriver.write_file, thendriver.complete_run; the canned artifacts are the correct proceed/park answers.Why
evals/skills-bundle/bundle.json,evals/skills-bundle/README.mdWhere: bundle.json L1-12, README v0.3.0 section L5-16.
What changed
Why
evals/scenarios/tier1-directory-full.jsonWhere:
skillBundle.versionL30.What changed
Why
evals/README.md,evals/fixture/README.mdWhere: evals/README.md L14-15, L24-27, L116-145 (Pre-1 kind section), L239; fixture/README.md L20, L37-39, L87-90.
What changed
decision_verdictmetric, the no-IAM fixture surface, and the 19-assertion verify count; Non-goals no longer list the two shipped skills.Why
Excluded
evals/runner/agent.test.ts,evals/runner/baseline.test.ts,evals/runner/run.test.ts,evals/runner/scenario.test.ts,evals/runner/score.test.ts,evals/runner/stages.test.ts,evals/runner/skills_bundle.test.ts,evals/runner/drivers/tier0/driver.test.ts— test-harness files covering the new pre1 behavior (scenario validation, P-gates, scoring, baseline skip, Tier-0 replays, prompt contract).