mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-18 13:53:01 +08:00
test: record Drupal profile and convergence methodology
This commit is contained in:
@@ -17,6 +17,9 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
### Extension preview
|
||||
|
||||
- Prepare immutable Drupal extension 0.1.1: ignore unrelated static receivers and commented/quoted declarations, and resolve both explicit Symfony event argument orders. Preserve the reviewed 0.1.0 artifact and policy.
|
||||
- Keep installed and selected marketplace versions distinct while compatibility metadata refreshes; pending requests no longer display an incompatible catalog version as installed.
|
||||
|
||||
- Add project-scoped framework and semantic extensions, managed package installation, worker loading, and graph refresh on install/update/enable/disable/remove. Failed activation preserves the previous project configuration and graph.
|
||||
- Add an external Drupal extension for declared routes/forms, services, hooks, plugins and event subscribers. Literal route paths can be explore endpoints; extension edges retain their labels and registration sites. Comments and quoted examples do not count as PHP invocations.
|
||||
- Add a local marketplace preview with signed publisher submissions, immutable releases, publisher ownership checks and a companion connection for project selection. Mobile detail pages retain version, compatibility and source information. Hosted deployment remains follow-up work; this is not a release announcement.
|
||||
|
||||
@@ -4,11 +4,26 @@
|
||||
queries in [Checking this file is still true](#checking-this-file-is-still-true)
|
||||
before trusting a row; this is a snapshot, not a live view.
|
||||
|
||||
**Extension preview, 2026-09-22:** the optional external Drupal package adds
|
||||
declared route/form handlers, service injection, literal hook/event dispatch
|
||||
and plugin implementation links. It does not add Drupal screen navigation or
|
||||
PHP branch guards. Scope and reproducible validation are recorded in
|
||||
[the extension recovery report](../validation/extensions-recovery-20260922.md).
|
||||
**Extension preview, 2026-09-22:** Drupal 0.1.1 supports explicit `_controller`
|
||||
and `_form` route defaults, unique YAML service classes/aliases and literal
|
||||
constructor arguments, literal service lookups, attached hook documentation or
|
||||
`Hook` attributes, explicit plugin IDs from attached annotations/attributes,
|
||||
and named event dispatch/subscriber links. Both Symfony `dispatch(name, event)`
|
||||
and `dispatch(event, name)` forms require an explicit literal/constant name.
|
||||
Commented calls, quoted declaration examples, unrelated `NotDrupal::service`,
|
||||
unknown targets, cyclic service aliases, computed IDs and duplicate plugin IDs
|
||||
are covered by negative checks.
|
||||
|
||||
The review samples 28 exact links across pinned Pathauto, Commerce and Drupal
|
||||
core, plus four unresolved corpus cases and focused synthetic positives/negatives.
|
||||
It is not an exhaustive precision/recall measurement. Dynamic entity forms,
|
||||
container factories/decorators, autowiring, computed dispatch names, single-argument
|
||||
object event inference, grouped imports and multiple namespaces per file are not
|
||||
certified. Receiver matching for hook/event/plugin APIs remains heuristic, not
|
||||
PHP runtime type analysis. No Drupal screen navigation or PHP branch guards are
|
||||
added. Immutable 0.1.0 is retained alongside 0.1.1. See the
|
||||
[Drupal review report](../validation/extensions-drupal-review-20260922.md) for
|
||||
exact source, measurements, exclusions and remaining limits.
|
||||
|
||||
This file exists to be read cold. It says, for every framework and language the
|
||||
README claims, **which of the three pictures it can draw today** and what is
|
||||
|
||||
@@ -4,9 +4,16 @@ The Cloudflare registry's public `/api/publish` endpoint cannot assign official
|
||||
|
||||
## Trust and immutable publication
|
||||
|
||||
`marketplace/cloudflare/official-policy.json` is a reviewed allowlist, committed alongside the operator. It pins Drupal `0.1.0`, package name, exact 289,167-byte artifact SHA-256, bundled entry hash, source repository/revision/path/hash and official metadata. The trusted identity is `publisherId: codegraph`, display name `CodeGraph`; it is distinct from the 64-hex SPKI identities assigned by community signatures. The policy is an operator trust decision anchored in reviewed source, **not a claim of a new signed upstream release**. Changing the policy requires review and a new immutable version when bytes change.
|
||||
`marketplace/cloudflare/official-policy.json` is a reviewed allowlist, committed alongside the operator. It retains Drupal `0.1.0` unchanged and adds the reviewed `0.1.1` accuracy revision. Each entry pins package name, version, byte length, artifact SHA-256, bundled entry hash, source repository/revision/path/hash and official metadata. The trusted identity is `publisherId: codegraph`, display name `CodeGraph`; it is distinct from the 64-hex SPKI identities assigned by community signatures. The policy is an operator trust decision anchored in reviewed source, **not a claim of a new signed upstream release**. Changing the policy requires review and a new immutable version when bytes change.
|
||||
|
||||
Artifact provenance: `dist/extensions/drupal.cgext` SHA-256 `e5015747d02fe50d6af607b6c44f1db9cf7969a0070866ed03c7643377a459c8`; source `extensions/drupal/index.cjs` at `37d4dd837120c1d56316c3cc65b6587b743a9112`. The existing `node scripts/build-extensions.mjs` build is reproducible with repository-locked dependencies. The command validates the complete artifact, supported extension API and the target engine version before any write, then enforces the pinned identity/integrity/entry provenance.
|
||||
Artifact provenance:
|
||||
|
||||
| Version | Artifact | SHA-256 | Reviewed source |
|
||||
|---|---|---|---|
|
||||
| 0.1.0 | `dist/extensions/drupal-0.1.0.cgext` (289,167 bytes) | `e5015747d02fe50d6af607b6c44f1db9cf7969a0070866ed03c7643377a459c8` | `37d4dd837120c1d56316c3cc65b6587b743a9112` |
|
||||
| 0.1.1 | `dist/extensions/drupal-0.1.1.cgext` (291,889 bytes); also current `drupal.cgext` | `e5ed73bee51524585e4f4da1d5017fdee3037a3fa71d8f08edab6c318fedc59a` | `b27bf875c95d3b82a0df411f68d0d8497993667b` |
|
||||
|
||||
The build preserves the archived 0.1.0 package under `extensions/drupal/releases/` and copies it byte-for-byte. `node scripts/build-extensions.mjs` builds 0.1.1 with repository-locked dependencies. The command validates the complete artifact, supported extension API and target engine before any write, then enforces pinned identity/integrity/entry provenance. Publish 0.1.1 as a new version; never replace 0.1.0. Both can coexist and repeated identical imports are idempotent.
|
||||
|
||||
Each plan includes an explicit registry identity and destination. `apply` requires the SHA-256 of the exact reviewed plan and validates its fields against the policy again. A different registry, unsupported engine, malformed artifact, changed plan, unexpected package or digest mismatch fails without publication. Plans and receipts contain public metadata and paths; credentials are never placed in either.
|
||||
|
||||
@@ -80,4 +87,4 @@ PLAYWRIGHT_MODULE=/absolute/path/to/playwright PATHAUTO_CORPUS=/absolute/pinned/
|
||||
|
||||
The browser test exports clean Pathauto source at `b97aadf47a37cff25f7d6105c3dade6778fccb47` into a disposable project. It uses the real CLI and local workerd/D1/R2, connects the browser once, clicks Install once, and verifies two route handlers, one hook and one service injection in actual SQLite. It proves malformed/incompatible/tampered failure preservation, disable/enable/remove cleanup, official catalog/detail/filter, and desktop/mobile layout. It does not modify the source corpus or rerun the larger corpus benchmark.
|
||||
|
||||
[Hosting/cost limits](cloudflare-hosting.md) remain unchanged: no durable Cloudflare URL, provider persistence, remote backup proof or Free-plan CPU fit is established. `marketplace.getcodegraph.com` remains proposed. Broader Drupal accuracy/performance review and current integrated full regression remain later milestones; historical measured overhead is 22–30%.
|
||||
[Hosting/cost limits](cloudflare-hosting.md) remain unchanged: no durable Cloudflare URL, provider persistence, remote backup proof or Free-plan CPU fit is established. `marketplace.getcodegraph.com` remains proposed. The Drupal review evidence is recorded separately; historical measured rebuild overhead was 22–30%, and local rebuild timings do not establish Workers Free CPU suitability.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Isolate the two versioned wiring callbacks over one identical, read-only
|
||||
// node/source snapshot. This is not a whole-index or graph-equivalence test.
|
||||
const fs=require('node:fs'),path=require('node:path'),os=require('node:os'),assert=require('node:assert/strict'),crypto=require('node:crypto');
|
||||
const {DatabaseSync}=require('node:sqlite');const {QueryBuilder}=require('../../dist/db/queries');
|
||||
const [project,output]=process.argv.slice(2),scratch=fs.mkdtempSync(path.join(os.tmpdir(),'drupal-pass-profile-'));
|
||||
const hash=b=>crypto.createHash('sha256').update(b).digest('hex');
|
||||
(async()=>{const db=new DatabaseSync(path.join(project,'.codegraph/codegraph.db'),{readOnly:true});
|
||||
try{
|
||||
const q=new QueryBuilder(db),all=q.getAllNodes(),byFile=new Map(),byName=new Map();
|
||||
for(const n of all){for(const [map,key]of [[byFile,n.filePath],[byName,n.name]]){if(!map.has(key))map.set(key,[]);map.get(key).push(n);}}
|
||||
const files=db.prepare('SELECT path FROM files ORDER BY path').all().map(f=>f.path),sources=new Map(files.map(f=>[f,fs.readFileSync(path.join(project,f),'utf8')]));
|
||||
const ctx={getAllFiles:()=>files,getNodesInFile:f=>byFile.get(f)||[],getNodesByName:n=>byName.get(n)||[],readFile:f=>sources.get(f)||null};
|
||||
const passes={},artifacts={};for(const v of ['0.1.0','0.1.1']){const bytes=fs.readFileSync(`dist/extensions/drupal-${v}.cgext`),p=JSON.parse(bytes),file=path.join(scratch,v+'.cjs');fs.writeFileSync(file,p.files[p.package.main]);passes[v]=require(file)().synthPasses[0];artifacts[v]=hash(bytes);}
|
||||
const record={project,files:files.length,nodes:all.length,artifacts,description:'Warm in-memory same snapshot; callback only; changed versions have intentionally different results',samples:[]};
|
||||
for(let iteration=1;iteration<=3;iteration++)for(const version of (iteration%2?['0.1.0','0.1.1']:['0.1.1','0.1.0'])){
|
||||
const cpu=process.cpuUsage(),start=performance.now();const edges=await passes[version].run(ctx,()=>new Promise(resolve=>setImmediate(resolve)));
|
||||
const sample={iteration,version,wallMs:performance.now()-start,cpu:process.cpuUsage(cpu),edges:edges.length,hash:hash(JSON.stringify(edges))};record.samples.push(sample);console.log(sample);
|
||||
const prior=record.samples.find(s=>s.version===version&&s!==sample);if(prior)assert.equal(sample.hash,prior.hash);
|
||||
fs.mkdirSync(path.dirname(output),{recursive:true});fs.writeFileSync(output,JSON.stringify(record,null,2));
|
||||
}
|
||||
}finally{db.close();fs.rmSync(scratch,{recursive:true,force:true});}
|
||||
})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
@@ -15,7 +15,7 @@ function snapshot(){const db=new DatabaseSync(path.join(project,'.codegraph/code
|
||||
for(const file of files)assert.ok(!fs.existsSync(path.join(project,file)));
|
||||
fs.writeFileSync(path.join(project,files[0]),`<?php
|
||||
namespace Drupal\\review;
|
||||
class ReviewSubscriber { public static function getSubscribedEvents() { return ['review.convergence' => 'onReview']; } public function onReview($event) {} }
|
||||
class ReviewSubscriber implements \\Symfony\\Component\\EventDispatcher\\EventSubscriberInterface { public static function getSubscribedEvents() { return ['review.convergence' => 'onReview']; } public function onReview($event) {} }
|
||||
class ReviewDispatch { public function send($dispatcher,$event) { $dispatcher->dispatch('review.convergence', $event); } }
|
||||
`);
|
||||
fs.writeFileSync(path.join(project,files[1]),"review.route:\n path: '/__review_unknown'\n defaults:\n _controller: '\\Missing\\Unknown::missing'\n");
|
||||
|
||||
Reference in New Issue
Block a user