feat(temporal): env-helper dispatch resolution — source-tiered defaults, allow-list, const-ref - #90
Conversation
d7eda41 to
ccb5db8
Compare
…ispatch fixes
Recognition + tiering core for the "AST recall → allow-list promote → LLM
clean" pipeline, bundled with three standalone dispatch fixes that live in
the same functions:
- Generic env-helper heuristic: any helper whose name contains "env"
(cfg.ActivityFromEnv("KEY","Default")) is recognised structurally and the
dispatch lands at the hidden speculative tier (temporal_env_source=heuristic).
- Source-tiered env-default: goTemporalEnvDefaultName now reports HOW it
resolved (os_getenv / allowlist / heuristic); the resolver tiers it —
allowlist/os_getenv → inferred 0.6 (visible), heuristic → speculative 0.4
(hidden). GoExtractor gains SetEnvHelperNames + an extra-allow-list param
threaded through the env-default recognition.
- GetEnvOrDefaultValue added to the built-in env-helper allow-list.
- Cross-repo *_test.go stub FP filter: a dispatch in repo A no longer
resolves to a test mock in repo B (isCrossRepoTestStub), the one confirmed
false positive from the corpus audit.
- Wrapper depth>1 fix: arg_names are now recorded for a forwarded lowercase
parameter, so the iterative wrapper pass follows a multi-hop chain to a
fixpoint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lets a corporate fork PROMOTE its own env-helper names from the generic "env"-name heuristic (hidden) to the allow-list tier (visible) without committing those names into the source tree. - config.LoadLocalTemporalEnvHelpers reads .gortex/temporal-allowlist.yaml (env_helpers:) ONLY under GORTEX_ALLOW_LOCAL_TEMPORAL=1, mirroring the providers.json repo-local opt-in. Fail-soft: missing gate / file / malformed yaml all yield no extra names. - languages.ConfigureTemporalEnvHelpers installs the loaded names onto the Go extractor; wired into `gortex index` (analyze wiring lands with the LLM pass). - .gortex/ added to .gitignore so the local allow-list and verdict cache are never committed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the zzet#1 corpus gap (per the design spec): an env-helper whose default argument is a constant reference rather than a string literal — `wfutil.GetEnvOrDefault(config.ACTIVITY_NAME_ENV, config.ACTIVITY_NAME_DEFAULT)`. - goArgDefaultValue reduces a default argument to its value: a literal (isConst=false) or a constant NAME — bare identifier or selector_expression (isConst=true). The three env-default extractors (os.Getenv-mixed, allow-list helper, env-name heuristic) all report it. - goTemporalEnvDefaultName returns the const name separately; the parser keeps temporal_name as the dispatch variable and emits temporal_default_const, with source=const_ref for trusted helpers (allow-list / os.Getenv) and source staying heuristic for an unproven env-named helper. - The resolver substitutes temporal_default_const through its existing constVal index (register-confirmed, then convention fallback). const_ref tiers as inferred 0.6 (visible), heuristic stays speculative 0.4 (hidden). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ccb5db8 to
cb6de90
Compare
|
Strong work on the tiering — the visible-vs-hidden split (os.Getenv / allow-list / const-ref → inferred 0.6; name-heuristic → speculative 0.4) is exactly the right call, and the Blocker: the allow-list never loads under the daemon / MCP ConfigureTemporalEnvHelpers is wired into exactly one place — the one-shot CLI: // cmd/gortex/index.go, runIndex()
languages.RegisterCustomGrammars(reg, cfg.Index.Grammars, idxLogger)
languages.RegisterExtractorPlugins(reg, cfg.Index.ExtractorPlugins, idxLogger)
languages.RegisterFallbackChunkers(reg, cfg.Index.FallbackChunkers, idxLogger)
languages.ConfigureTemporalEnvHelpers(reg, config.LoadLocalTemporalEnvHelpers(path)) // ← only hereBut the daemon — the primary path for MCP/agent usage — builds its own registry and never calls it: // internal/serverstack/shared_server.go:233-239
reg := parser.NewRegistry()
languages.RegisterAll(reg)
languages.RegisterCustomGrammars(reg, conf.Index.Grammars, logger)
languages.RegisterExtractorPlugins(reg, conf.Index.ExtractorPlugins, logger)
languages.RegisterFallbackChunkers(reg, conf.Index.FallbackChunkers, logger)
// no ConfigureTemporalEnvHelpers
idx := indexer.New(g, reg, conf.Index, logger)…and so does the crash-isolated parse worker: // internal/parser/crashpool/worker.go, RunWorker()
reg := parser.NewRegistry()
languages.RegisterAll(reg)
registerWorkerGrammars(reg)
registerWorkerExtractorPlugins(reg)
registerWorkerFallbackChunkers(reg)
// no env-helper equivalentNet effect: under gortex daemon / MCP, the repo-local allow-list is silently inert — only the built-in In fairness: the three sibling helpers are also CLI-only today, so this isn't a regression — it follows an existing pattern. But the allow-list is the headline of commit 2, so it should actually be reachable from the daemon before we call it done. Why a naive "just add the call to the daemon" won't fully work The allow-list is stored as instance state on a process-shared singleton:
So Suggested resolution Smaller question
Happy either way — just want the choice to be intentional. Everything else (tiering, const-ref, wrapper fixpoint, the _test.go cross-repo stub filter) looks good to me. Resolve the wiring story and I think this is ready. |
Reconcile env-helper dispatch resolution with the convention fallback now on main: - temporal_calls.go ladder keeps both tiers (env-default const-ref → convention fallback) before the cross-language join - lookupConvention now drops cross-repo *_test.go stubs like the register path, so a convention match never lands on a cross-repo test fixture - reconstructed the two appended e2e tests (WrapperDepth2 + unregistered- by-convention) as separate functions
Reconcile var-trace / const-alias / exact-name signature dispatch (zzet#98) with the convention (zzet#89) and env-helper (zzet#90) tiers now on main: - resolution ladder keeps exactSig (speculative) after the cross-language join; the env-default tier-override now also covers var_trace origins and preserves zzet#90's source-tiering (allowlist/os_getenv/const_ref stay visible) - single temporal_resolution_via stamp (exact_sig | convention) instead of two blocks that clobbered each other - fold the funcExact (zzet#98) and funcByName (zzet#89) indexes into one node sweep - goConstLiteralValue: keep main's grouped-const selection (drop zzet#98's equivalent duplicate) - lookupConvention drops cross-repo *_test.go stubs (matches main's fix) - regression test for parallel-assignment var-trace (x, act := _, "Name")
Reconcile Java cross-language dispatch (zzet#97) with var-trace/env-helper/ convention resolver now on main: - buildConstDerefMap unified: keep main's const-alias following (aliasRef + bounded fixpoint) AND zzet#97's Java string-field collection (javaFieldVals), both feeding one order-independent ingest with the shared ambiguity rule; no early-return on a non-ConstantValueReader store so Java fields still load - register.go keeps both ConfigureTemporalJavaInvokers (zzet#97) and ConfigureTemporalEnvHelpers (zzet#90) - temporal_e2e_test.go is the union of both test sets (4 Java cross-lang tests added alongside main's var-trace/convention/env tests)
What
Brings Temporal env-helper dispatch resolution onto current
main, as a 3-commit stack (kept separate for commit-by-commit review):GetEnvOr("ACTIVITY", "Default")-style) and resolve the dispatch name from the literal default, tiered by source confidence:os.Getenv→ visible,OriginASTInferred@ 0.6OriginSpeculative@ 0.4Also fixes wrapper depth>1 (forwarded-param stubs now resolve via a bounded fixpoint).
.gortex/temporal-allowlist.yaml(git-ignored, opt-in) lets a repo declare its own env-helper function names so their defaults resolve at the visible tier. Config-only, applied cleanly.GetEnvOr("ACTIVITY", constants.DEFAULT_NAME)where the default is a const reference, by dereferencing it through the const-deref map.Why
Dispatch names sourced from env-var-with-default helpers were left
broken_dispatch. This recovers them while being honest about confidence: a config-confirmed/os.Getenvdefault is trustworthy (visible), a name-only heuristic is a guess (speculative/hidden), so it never pollutes high-confidence results.Porting notes (post-#82)
PR #82 refactored the resolver (4-arg
idx.lookup(kind, name, callerRepo, callerLang), replay-loopgoTemporalEnvDefaultName, removedconstVal/convention helpers). The stack was re-applied onto that structure:MetaSpeculativenow keyed onenvSpeculative||crossLangso visible env-defaults aren't hidden.derefByName/buildConstDerefMap(replacing the removedconstVal).eligibleTemporalCandidatescross-repo*_test.gostub filter kept on the surviving register-confirmed path.Behavioral note for reviewers
PR #82 silently dropped the "unregistered activity resolves via name convention" guarantee; the two resolver tests here document the registered-path behavior instead (the cross-repo test-stub filter is verified load-bearing). The separate convention fallback is proposed in its own PR (#89).
Tests
New: allow-list config tests, 5 env-helper extractor tests, 3 const-ref tests, env-heuristic + wrapper-depth-2 e2e.
go build ./...,go vet, and-raceclean; resolver / parser / indexer / config suites pass.